1use clap::{error::ErrorKind, ArgAction, Command};
2
3use crate::utils;
4
5fn common() -> Command {
6    Command::new("foo").help_template(utils::FULL_TEMPLATE)
7}
8
9fn with_version() -> Command {
10    common().version("3.0")
11}
12
13fn with_long_version() -> Command {
14    common().long_version("3.0 (abcdefg)")
15}
16
17fn with_both() -> Command {
18    common().version("3.0").long_version("3.0 (abcdefg)")
19}
20
21fn with_subcommand() -> Command {
22    with_version().subcommand(Command::new("bar").subcommand(Command::new("baz")))
23}
24
25#[test]
26fn version_short_flag_no_version() {
27    let res = common().try_get_matches_from("foo -V".split(' '));
28
29    assert!(res.is_err());
30    let err = res.unwrap_err();
31    assert_eq!(err.kind(), clap::error::ErrorKind::UnknownArgument);
32}
33
34#[test]
35fn version_long_flag_no_version() {
36    let res = common().try_get_matches_from("foo --version".split(' '));
37
38    assert!(res.is_err());
39    let err = res.unwrap_err();
40    assert_eq!(err.kind(), clap::error::ErrorKind::UnknownArgument);
41}
42
43#[test]
44fn version_short_flag_with_version() {
45    let res = with_version().try_get_matches_from("foo -V".split(' '));
46
47    assert!(res.is_err());
48    let err = res.unwrap_err();
49    assert_eq!(err.kind(), ErrorKind::DisplayVersion);
50    assert_eq!(err.to_string(), "foo 3.0\n");
51}
52
53#[test]
54fn version_long_flag_with_version() {
55    let res = with_version().try_get_matches_from("foo --version".split(' '));
56
57    assert!(res.is_err());
58    let err = res.unwrap_err();
59    assert_eq!(err.kind(), ErrorKind::DisplayVersion);
60    assert_eq!(err.to_string(), "foo 3.0\n");
61}
62
63#[test]
64fn version_short_flag_with_long_version() {
65    let res = with_long_version().try_get_matches_from("foo -V".split(' '));
66
67    assert!(res.is_err());
68    let err = res.unwrap_err();
69    assert_eq!(err.kind(), ErrorKind::DisplayVersion);
70    assert_eq!(err.to_string(), "foo 3.0 (abcdefg)\n");
71}
72
73#[test]
74fn version_long_flag_with_long_version() {
75    let res = with_long_version().try_get_matches_from("foo --version".split(' '));
76
77    assert!(res.is_err());
78    let err = res.unwrap_err();
79    assert_eq!(err.kind(), ErrorKind::DisplayVersion);
80    assert_eq!(err.to_string(), "foo 3.0 (abcdefg)\n");
81}
82
83#[test]
84fn version_short_flag_with_both() {
85    let res = with_both().try_get_matches_from("foo -V".split(' '));
86
87    assert!(res.is_err());
88    let err = res.unwrap_err();
89    assert_eq!(err.kind(), ErrorKind::DisplayVersion);
90    assert_eq!(err.to_string(), "foo 3.0\n");
91}
92
93#[test]
94fn version_long_flag_with_both() {
95    let res = with_both().try_get_matches_from("foo --version".split(' '));
96
97    assert!(res.is_err());
98    let err = res.unwrap_err();
99    assert_eq!(err.kind(), ErrorKind::DisplayVersion);
100    assert_eq!(err.to_string(), "foo 3.0 (abcdefg)\n");
101}
102
103#[test]
104fn help_short_flag_no_version() {
105    static EXPECTED: &str = "\
106foo
107
108Usage: foo
109
110Options:
111  -h, --help  Print help
112";
113    let cmd = common();
114    utils::assert_output(cmd, "foo -h", EXPECTED, false);
115}
116
117#[test]
118fn help_long_flag_no_version() {
119    static EXPECTED: &str = "\
120foo
121
122Usage: foo
123
124Options:
125  -h, --help  Print help
126";
127    let cmd = common();
128    utils::assert_output(cmd, "foo --help", EXPECTED, false);
129}
130
131#[test]
132fn help_short_flag_with_version() {
133    static EXPECTED: &str = "\
134foo 3.0
135
136Usage: foo
137
138Options:
139  -h, --help     Print help
140  -V, --version  Print version
141";
142    let cmd = with_version();
143    utils::assert_output(cmd, "foo -h", EXPECTED, false);
144}
145
146#[test]
147fn help_long_flag_with_version() {
148    static EXPECTED: &str = "\
149foo 3.0
150
151Usage: foo
152
153Options:
154  -h, --help     Print help
155  -V, --version  Print version
156";
157    let cmd = with_version();
158    utils::assert_output(cmd, "foo --help", EXPECTED, false);
159}
160
161#[test]
162fn help_short_flag_with_long_version() {
163    static EXPECTED: &str = "\
164foo 3.0 (abcdefg)
165
166Usage: foo
167
168Options:
169  -h, --help     Print help
170  -V, --version  Print version
171";
172    let cmd = with_long_version();
173    utils::assert_output(cmd, "foo -h", EXPECTED, false);
174}
175
176#[test]
177fn help_long_flag_with_long_version() {
178    static EXPECTED: &str = "\
179foo 3.0 (abcdefg)
180
181Usage: foo
182
183Options:
184  -h, --help     Print help
185  -V, --version  Print version
186";
187    let cmd = with_long_version();
188    utils::assert_output(cmd, "foo --help", EXPECTED, false);
189}
190
191#[test]
192fn help_short_flag_with_both() {
193    static EXPECTED: &str = "\
194foo 3.0
195
196Usage: foo
197
198Options:
199  -h, --help     Print help
200  -V, --version  Print version
201";
202    let cmd = with_both();
203    utils::assert_output(cmd, "foo -h", EXPECTED, false);
204}
205
206#[test]
207fn help_long_flag_with_both() {
208    static EXPECTED: &str = "\
209foo 3.0
210
211Usage: foo
212
213Options:
214  -h, --help     Print help
215  -V, --version  Print version
216";
217    let cmd = with_both();
218    utils::assert_output(cmd, "foo --help", EXPECTED, false);
219}
220
221#[test]
222#[cfg(debug_assertions)]
223#[should_panic = "Command foo: Long option names must be unique for each argument, but '--version' is in use by both 'ver' and 'version' (call `cmd.disable_version_flag(true)` to remove the auto-generated `--version`)"]
224fn override_version_long_with_user_flag() {
225    with_version()
226        .arg(
227            clap::Arg::new("ver")
228                .long("version")
229                .action(ArgAction::SetTrue),
230        )
231        .debug_assert();
232}
233
234#[test]
235#[cfg(debug_assertions)]
236#[should_panic = "Command foo: Short option names must be unique for each argument, but '-V' is in use by both 'ver' and 'version' (call `cmd.disable_version_flag(true)` to remove the auto-generated `--version`)"]
237fn override_version_short_with_user_flag() {
238    with_version()
239        .arg(clap::Arg::new("ver").short('V').action(ArgAction::SetTrue))
240        .debug_assert();
241}
242
243#[test]
244fn no_propagation_by_default_long() {
245    // Version Flag should not be propagated to subcommands
246    let res = with_subcommand().try_get_matches_from("foo bar --version".split(' '));
247
248    assert!(res.is_err());
249    let err = res.unwrap_err();
250    assert_eq!(err.kind(), ErrorKind::UnknownArgument);
251}
252
253#[test]
254fn no_propagation_by_default_short() {
255    let res = with_subcommand().try_get_matches_from("foo bar -V".split(' '));
256
257    assert!(res.is_err());
258    let err = res.unwrap_err();
259    assert_eq!(err.kind(), ErrorKind::UnknownArgument);
260}
261
262#[test]
263fn propagate_version_long() {
264    let res = with_subcommand()
265        .propagate_version(true)
266        .try_get_matches_from("foo bar --version".split(' '));
267
268    assert!(res.is_err());
269    let err = res.unwrap_err();
270    assert_eq!(err.kind(), ErrorKind::DisplayVersion);
271}
272
273#[test]
274fn propagate_version_short() {
275    let res = with_subcommand()
276        .propagate_version(true)
277        .try_get_matches_from("foo bar -V".split(' '));
278
279    assert!(res.is_err());
280    let err = res.unwrap_err();
281    assert_eq!(err.kind(), ErrorKind::DisplayVersion);
282}
283
284#[cfg(debug_assertions)]
285#[test]
286#[should_panic = "`ArgAction::Version` used without providing Command::version or Command::long_version"]
287fn version_required() {
288    let _res = common()
289        .arg(clap::arg!(--version).action(ArgAction::Version))
290        .try_get_matches_from("foo -z".split(' '));
291}
292
293#[test]
294#[should_panic = "Argument `version` is undefined"]
295fn mut_arg_version_no_auto_version() {
296    let _ = common().mut_arg("version", |v| v.short('z').action(ArgAction::SetTrue));
297}
298
299#[cfg(debug_assertions)]
300#[test]
301#[should_panic = "No version information via Command::version or Command::long_version to propagate"]
302fn propagate_version_no_version_info() {
303    let _res = common()
304        .propagate_version(true)
305        .subcommand(Command::new("bar"))
306        .try_get_matches_from("foo".split(' '));
307}
308