1 use clap::{Arg, ArgAction, ArgMatches, Command};
2
get_app() -> Command3 fn get_app() -> Command {
4 Command::new("myprog")
5 .arg(
6 Arg::new("GLOBAL_ARG")
7 .long("global-arg")
8 .help("Specifies something needed by the subcommands")
9 .global(true)
10 .action(ArgAction::Set)
11 .default_value("default_value"),
12 )
13 .arg(
14 Arg::new("GLOBAL_FLAG")
15 .long("global-flag")
16 .help("Specifies something needed by the subcommands")
17 .global(true)
18 .action(ArgAction::Count),
19 )
20 .subcommand(Command::new("outer").subcommand(Command::new("inner")))
21 }
22
get_matches(cmd: Command, argv: &'static str) -> ArgMatches23 fn get_matches(cmd: Command, argv: &'static str) -> ArgMatches {
24 cmd.try_get_matches_from(argv.split(' ').collect::<Vec<_>>())
25 .unwrap()
26 }
27
get_outer_matches(m: &ArgMatches) -> &ArgMatches28 fn get_outer_matches(m: &ArgMatches) -> &ArgMatches {
29 m.subcommand_matches("outer")
30 .expect("could not access outer subcommand")
31 }
32
get_inner_matches(m: &ArgMatches) -> &ArgMatches33 fn get_inner_matches(m: &ArgMatches) -> &ArgMatches {
34 get_outer_matches(m)
35 .subcommand_matches("inner")
36 .expect("could not access inner subcommand")
37 }
38
top_can_access_arg<T: Into<Option<&'static str>>>(m: &ArgMatches, val: T) -> bool39 fn top_can_access_arg<T: Into<Option<&'static str>>>(m: &ArgMatches, val: T) -> bool {
40 m.get_one::<String>("GLOBAL_ARG").map(|v| v.as_str()) == val.into()
41 }
42
inner_can_access_arg<T: Into<Option<&'static str>>>(m: &ArgMatches, val: T) -> bool43 fn inner_can_access_arg<T: Into<Option<&'static str>>>(m: &ArgMatches, val: T) -> bool {
44 get_inner_matches(m)
45 .get_one::<String>("GLOBAL_ARG")
46 .map(|v| v.as_str())
47 == val.into()
48 }
49
outer_can_access_arg<T: Into<Option<&'static str>>>(m: &ArgMatches, val: T) -> bool50 fn outer_can_access_arg<T: Into<Option<&'static str>>>(m: &ArgMatches, val: T) -> bool {
51 get_outer_matches(m)
52 .get_one::<String>("GLOBAL_ARG")
53 .map(|v| v.as_str())
54 == val.into()
55 }
56
top_can_access_flag(m: &ArgMatches, present: bool, occurrences: u8) -> bool57 fn top_can_access_flag(m: &ArgMatches, present: bool, occurrences: u8) -> bool {
58 (m.contains_id("GLOBAL_FLAG") == present)
59 && (m.get_one::<u8>("GLOBAL_FLAG").copied() == Some(occurrences))
60 }
61
inner_can_access_flag(m: &ArgMatches, present: bool, occurrences: u8) -> bool62 fn inner_can_access_flag(m: &ArgMatches, present: bool, occurrences: u8) -> bool {
63 let m = get_inner_matches(m);
64 (m.contains_id("GLOBAL_FLAG") == present)
65 && (m.get_one::<u8>("GLOBAL_FLAG").copied() == Some(occurrences))
66 }
67
outer_can_access_flag(m: &ArgMatches, present: bool, occurrences: u8) -> bool68 fn outer_can_access_flag(m: &ArgMatches, present: bool, occurrences: u8) -> bool {
69 let m = get_outer_matches(m);
70 (m.contains_id("GLOBAL_FLAG") == present)
71 && (m.get_one::<u8>("GLOBAL_FLAG").copied() == Some(occurrences))
72 }
73
74 #[test]
global_arg_used_top_level()75 fn global_arg_used_top_level() {
76 let m = get_matches(get_app(), "myprog --global-arg=some_value outer inner");
77
78 assert!(top_can_access_arg(&m, "some_value"));
79 assert!(inner_can_access_arg(&m, "some_value"));
80 assert!(outer_can_access_arg(&m, "some_value"));
81 }
82
83 #[test]
global_arg_used_outer()84 fn global_arg_used_outer() {
85 let m = get_matches(get_app(), "myprog outer --global-arg=some_value inner");
86
87 assert!(top_can_access_arg(&m, "some_value"));
88 assert!(inner_can_access_arg(&m, "some_value"));
89 assert!(outer_can_access_arg(&m, "some_value"));
90 }
91
92 #[test]
global_arg_used_inner()93 fn global_arg_used_inner() {
94 let m = get_matches(get_app(), "myprog outer inner --global-arg=some_value");
95
96 assert!(top_can_access_arg(&m, "some_value"));
97 assert!(inner_can_access_arg(&m, "some_value"));
98 assert!(outer_can_access_arg(&m, "some_value"));
99 }
100
101 #[test]
global_arg_default_value()102 fn global_arg_default_value() {
103 let m = get_matches(get_app(), "myprog outer inner");
104
105 assert!(top_can_access_arg(&m, "default_value"));
106 assert!(inner_can_access_arg(&m, "default_value"));
107 assert!(outer_can_access_arg(&m, "default_value"));
108 }
109
110 #[test]
global_flag_used_top_level()111 fn global_flag_used_top_level() {
112 let m = get_matches(get_app(), "myprog --global-flag outer inner");
113
114 assert!(top_can_access_flag(&m, true, 1));
115 assert!(inner_can_access_flag(&m, true, 1));
116 assert!(outer_can_access_flag(&m, true, 1));
117 }
118
119 #[test]
global_flag_used_outer()120 fn global_flag_used_outer() {
121 let m = get_matches(get_app(), "myprog outer --global-flag inner");
122
123 assert!(top_can_access_flag(&m, true, 1));
124 assert!(inner_can_access_flag(&m, true, 1));
125 assert!(outer_can_access_flag(&m, true, 1));
126 }
127
128 #[test]
global_flag_used_inner()129 fn global_flag_used_inner() {
130 let m = get_matches(get_app(), "myprog outer inner --global-flag");
131
132 assert!(top_can_access_flag(&m, true, 1));
133 assert!(inner_can_access_flag(&m, true, 1));
134 assert!(outer_can_access_flag(&m, true, 1));
135 }
136
137 #[test]
global_flag_2x_used_top_level()138 fn global_flag_2x_used_top_level() {
139 let m = get_matches(get_app(), "myprog --global-flag --global-flag outer inner");
140
141 assert!(top_can_access_flag(&m, true, 2));
142 assert!(inner_can_access_flag(&m, true, 2));
143 assert!(outer_can_access_flag(&m, true, 2));
144 }
145
146 #[test]
global_flag_2x_used_inner()147 fn global_flag_2x_used_inner() {
148 let m = get_matches(get_app(), "myprog outer inner --global-flag --global-flag");
149
150 assert!(top_can_access_flag(&m, true, 2));
151 assert!(inner_can_access_flag(&m, true, 2));
152 assert!(outer_can_access_flag(&m, true, 2));
153 }
154