1 use clap::{arg, Arg, ArgAction, Command};
2
3 #[test]
opt_missing()4 fn opt_missing() {
5 let r = Command::new("df")
6 .arg(
7 Arg::new("color")
8 .long("color")
9 .default_value("auto")
10 .num_args(0..=1)
11 .require_equals(true)
12 .default_missing_value("always"),
13 )
14 .try_get_matches_from(vec![""]);
15 assert!(r.is_ok(), "{}", r.unwrap_err());
16 let m = r.unwrap();
17 assert!(m.contains_id("color"));
18 assert_eq!(
19 m.get_one::<String>("color").map(|v| v.as_str()).unwrap(),
20 "auto"
21 );
22 assert_eq!(
23 m.value_source("color").unwrap(),
24 clap::parser::ValueSource::DefaultValue
25 );
26 assert_eq!(m.index_of("color"), Some(1));
27 }
28
29 #[test]
opt_present_with_missing_value()30 fn opt_present_with_missing_value() {
31 let r = Command::new("df")
32 .arg(
33 Arg::new("color")
34 .long("color")
35 .default_value("auto")
36 .num_args(0..=1)
37 .require_equals(true)
38 .default_missing_value("always"),
39 )
40 .try_get_matches_from(vec!["", "--color"]);
41 assert!(r.is_ok(), "{}", r.unwrap_err());
42 let m = r.unwrap();
43 assert!(m.contains_id("color"));
44 assert_eq!(
45 m.get_one::<String>("color").map(|v| v.as_str()).unwrap(),
46 "always"
47 );
48 assert_eq!(
49 m.value_source("color").unwrap(),
50 clap::parser::ValueSource::CommandLine
51 );
52 assert_eq!(m.index_of("color"), Some(2));
53 }
54
55 #[test]
opt_present_with_value()56 fn opt_present_with_value() {
57 let r = Command::new("df")
58 .arg(
59 Arg::new("color")
60 .long("color")
61 .default_value("auto")
62 .num_args(0..=1)
63 .require_equals(true)
64 .default_missing_value("always"),
65 )
66 .try_get_matches_from(vec!["", "--color=never"]);
67 assert!(r.is_ok(), "{}", r.unwrap_err());
68 let m = r.unwrap();
69 assert!(m.contains_id("color"));
70 assert_eq!(
71 m.get_one::<String>("color").map(|v| v.as_str()).unwrap(),
72 "never"
73 );
74 assert_eq!(
75 m.value_source("color").unwrap(),
76 clap::parser::ValueSource::CommandLine
77 );
78 assert_eq!(m.index_of("color"), Some(2));
79 }
80
81 #[test]
opt_present_with_empty_value()82 fn opt_present_with_empty_value() {
83 let r = Command::new("df")
84 .arg(
85 Arg::new("color")
86 .long("color")
87 .default_value("auto")
88 .require_equals(true)
89 .default_missing_value("always"),
90 )
91 .try_get_matches_from(vec!["", "--color="]);
92 assert!(r.is_ok(), "{}", r.unwrap_err());
93 let m = r.unwrap();
94 assert!(m.contains_id("color"));
95 assert_eq!(
96 m.get_one::<String>("color").map(|v| v.as_str()).unwrap(),
97 ""
98 );
99 assert_eq!(
100 m.value_source("color").unwrap(),
101 clap::parser::ValueSource::CommandLine
102 );
103 assert_eq!(m.index_of("color"), Some(2));
104 }
105
106 //## `default_value`/`default_missing_value` non-interaction checks
107
108 #[test]
opt_default()109 fn opt_default() {
110 // assert no change to usual argument handling when adding default_missing_value()
111 let r = Command::new("cmd")
112 .arg(
113 arg!(o: -o [opt] "some opt")
114 .default_value("default")
115 .default_missing_value("default_missing"),
116 )
117 .try_get_matches_from(vec![""]);
118 assert!(r.is_ok(), "{}", r.unwrap_err());
119 let m = r.unwrap();
120 assert!(m.contains_id("o"));
121 assert_eq!(
122 m.get_one::<String>("o").map(|v| v.as_str()).unwrap(),
123 "default"
124 );
125 }
126
127 #[test]
opt_default_user_override()128 fn opt_default_user_override() {
129 // assert no change to usual argument handling when adding default_missing_value()
130 let r = Command::new("cmd")
131 .arg(
132 arg!(o: -o [opt] "some opt")
133 .default_value("default")
134 .default_missing_value("default_missing"),
135 )
136 .try_get_matches_from(vec!["", "-o=value"]);
137 assert!(r.is_ok(), "{}", r.unwrap_err());
138 let m = r.unwrap();
139 assert!(m.contains_id("o"));
140 assert_eq!(
141 m.get_one::<String>("o").map(|v| v.as_str()).unwrap(),
142 "value"
143 );
144 }
145
146 #[test]
default_missing_value_per_occurrence()147 fn default_missing_value_per_occurrence() {
148 // assert no change to usual argument handling when adding default_missing_value()
149 let r = Command::new("cmd")
150 .arg(
151 arg!(o: -o [opt] ... "some opt")
152 .default_value("default")
153 .default_missing_value("default_missing"),
154 )
155 .try_get_matches_from(vec!["", "-o", "-o=value", "-o"]);
156 assert!(r.is_ok(), "{}", r.unwrap_err());
157 let m = r.unwrap();
158 assert_eq!(
159 m.get_many::<String>("o")
160 .unwrap()
161 .map(|v| v.as_str())
162 .collect::<Vec<_>>(),
163 vec!["default_missing", "value", "default_missing"]
164 );
165 }
166
167 #[test]
168 #[allow(clippy::bool_assert_comparison)]
default_missing_value_flag_value()169 fn default_missing_value_flag_value() {
170 let cmd = Command::new("test").arg(
171 Arg::new("flag")
172 .long("flag")
173 .action(ArgAction::Set)
174 .num_args(0..=1)
175 .default_value("false")
176 .default_missing_value("true"),
177 );
178
179 let m = cmd.clone().try_get_matches_from(["test"]).unwrap();
180 assert!(m.contains_id("flag"));
181 assert_eq!(
182 m.get_one::<String>("flag").map(|v| v.as_str()),
183 Some("false")
184 );
185 assert_eq!(
186 m.value_source("flag").unwrap(),
187 clap::parser::ValueSource::DefaultValue
188 );
189
190 let m = cmd
191 .clone()
192 .try_get_matches_from(["test", "--flag"])
193 .unwrap();
194 assert!(m.contains_id("flag"));
195 assert_eq!(
196 m.get_one::<String>("flag").map(|v| v.as_str()),
197 Some("true")
198 );
199 assert_eq!(
200 m.value_source("flag").unwrap(),
201 clap::parser::ValueSource::CommandLine
202 );
203
204 let m = cmd
205 .clone()
206 .try_get_matches_from(["test", "--flag=true"])
207 .unwrap();
208 assert!(m.contains_id("flag"));
209 assert_eq!(
210 m.get_one::<String>("flag").map(|v| v.as_str()),
211 Some("true")
212 );
213 assert_eq!(
214 m.value_source("flag").unwrap(),
215 clap::parser::ValueSource::CommandLine
216 );
217
218 let m = cmd.try_get_matches_from(["test", "--flag=false"]).unwrap();
219 assert!(m.contains_id("flag"));
220 assert_eq!(
221 m.get_one::<String>("flag").map(|v| v.as_str()),
222 Some("false")
223 );
224 assert_eq!(
225 m.value_source("flag").unwrap(),
226 clap::parser::ValueSource::CommandLine
227 );
228 }
229
230 #[test]
delimited_missing_value()231 fn delimited_missing_value() {
232 let cmd = Command::new("test").arg(
233 Arg::new("flag")
234 .long("flag")
235 .default_value("one,two")
236 .default_missing_value("three,four")
237 .num_args(0..)
238 .value_delimiter(',')
239 .require_equals(true),
240 );
241
242 let m = cmd.clone().try_get_matches_from(["test"]).unwrap();
243 assert_eq!(
244 m.get_many::<String>("flag")
245 .unwrap()
246 .map(|s| s.as_str())
247 .collect::<Vec<_>>(),
248 vec!["one", "two"]
249 );
250
251 let m = cmd.try_get_matches_from(["test", "--flag"]).unwrap();
252 assert_eq!(
253 m.get_many::<String>("flag")
254 .unwrap()
255 .map(|s| s.as_str())
256 .collect::<Vec<_>>(),
257 vec!["three", "four"]
258 );
259 }
260
261 #[cfg(debug_assertions)]
262 #[test]
263 #[cfg(feature = "error-context")]
264 #[should_panic = "Argument `arg`'s default_missing_value=\"value\" failed validation: error: invalid value 'value' for '[arg]'"]
default_missing_values_are_possible_values()265 fn default_missing_values_are_possible_values() {
266 use clap::{Arg, Command};
267
268 let _ = Command::new("test")
269 .arg(
270 Arg::new("arg")
271 .value_parser(["one", "two"])
272 .default_missing_value("value"),
273 )
274 .try_get_matches();
275 }
276
277 #[cfg(debug_assertions)]
278 #[test]
279 #[cfg(feature = "error-context")]
280 #[should_panic = "Argument `arg`'s default_missing_value=\"value\" failed validation: error: invalid value 'value' for '[arg]"]
default_missing_values_are_valid()281 fn default_missing_values_are_valid() {
282 use clap::{Arg, Command};
283
284 let _ = Command::new("test")
285 .arg(
286 Arg::new("arg")
287 .value_parser(clap::value_parser!(u32))
288 .default_missing_value("value"),
289 )
290 .try_get_matches();
291 }
292
293 #[test]
valid_index()294 fn valid_index() {
295 let m = Command::new("df")
296 .arg(
297 Arg::new("color")
298 .long("color")
299 .default_value("auto")
300 .num_args(0..=1)
301 .require_equals(true)
302 .default_missing_value("always"),
303 )
304 .arg(Arg::new("sync").long("sync").action(ArgAction::SetTrue))
305 .try_get_matches_from(vec!["df", "--color", "--sync"])
306 .unwrap();
307 assert!(m.contains_id("color"));
308 assert_eq!(
309 m.get_one::<String>("color").map(|v| v.as_str()).unwrap(),
310 "always"
311 );
312 assert_eq!(
313 m.value_source("color").unwrap(),
314 clap::parser::ValueSource::CommandLine
315 );
316
317 // Make sure the index reflects `--color`s position and not something else
318 assert_eq!(m.index_of("color"), Some(2));
319 }
320