1use super::utils; 2 3use std::io::Write; 4use std::str; 5 6use clap::{Arg, Command}; 7 8static SCF2OP: &str = "flag present 2 times 9option NOT present 10positional NOT present 11flag2 NOT present 12option2 maybe present with value of: Nothing 13positional2 maybe present with value of: Nothing 14option3 NOT present 15positional3 NOT present 16option NOT present 17positional NOT present 18subcmd present 19flag present 2 times 20scoption present with value: some 21An scoption: some 22scpositional present with value: value 23"; 24 25static SCFOP: &str = "flag present 1 times 26option NOT present 27positional NOT present 28flag2 NOT present 29option2 maybe present with value of: Nothing 30positional2 maybe present with value of: Nothing 31option3 NOT present 32positional3 NOT present 33option NOT present 34positional NOT present 35subcmd present 36flag present 1 times 37scoption present with value: some 38An scoption: some 39scpositional present with value: value 40"; 41 42static O2P: &str = "flag NOT present 43option present with value: some 44An option: some 45An option: other 46positional present with value: value 47flag2 NOT present 48option2 maybe present with value of: Nothing 49positional2 maybe present with value of: Nothing 50option3 NOT present 51positional3 NOT present 52option present with value: some 53An option: some 54An option: other 55positional present with value: value 56subcmd NOT present 57"; 58 59static F2OP: &str = "flag present 2 times 60option present with value: some 61An option: some 62positional present with value: value 63flag2 NOT present 64option2 maybe present with value of: Nothing 65positional2 maybe present with value of: Nothing 66option3 NOT present 67positional3 NOT present 68option present with value: some 69An option: some 70positional present with value: value 71subcmd NOT present 72"; 73 74static FOP: &str = "flag present 1 times 75option present with value: some 76An option: some 77positional present with value: value 78flag2 NOT present 79option2 maybe present with value of: Nothing 80positional2 maybe present with value of: Nothing 81option3 NOT present 82positional3 NOT present 83option present with value: some 84An option: some 85positional present with value: value 86subcmd NOT present 87"; 88 89pub fn check_complex_output(args: &str, out: &str) { 90 let mut w = vec![]; 91 let matches = utils::complex_app() 92 .try_get_matches_from(args.split(' ').collect::<Vec<_>>()) 93 .unwrap(); 94 match matches.get_one::<u8>("flag").unwrap() { 95 0 => { 96 writeln!(w, "flag NOT present").unwrap(); 97 } 98 n => { 99 writeln!(w, "flag present {} times", n).unwrap(); 100 } 101 } 102 103 if matches.contains_id("option") { 104 if let Some(v) = matches.get_one::<String>("option").map(|v| v.as_str()) { 105 writeln!(w, "option present with value: {}", v).unwrap(); 106 } 107 if let Some(ov) = matches.get_many::<String>("option") { 108 for o in ov { 109 writeln!(w, "An option: {}", o).unwrap(); 110 } 111 } 112 } else { 113 writeln!(w, "option NOT present").unwrap(); 114 } 115 116 if let Some(p) = matches.get_one::<String>("positional").map(|v| v.as_str()) { 117 writeln!(w, "positional present with value: {}", p).unwrap(); 118 } else { 119 writeln!(w, "positional NOT present").unwrap(); 120 } 121 122 if *matches.get_one::<bool>("flag2").expect("defaulted by clap") { 123 writeln!(w, "flag2 present").unwrap(); 124 writeln!( 125 w, 126 "option2 present with value of: {}", 127 matches 128 .get_one::<String>("long-option-2") 129 .map(|v| v.as_str()) 130 .unwrap() 131 ) 132 .unwrap(); 133 writeln!( 134 w, 135 "positional2 present with value of: {}", 136 matches 137 .get_one::<String>("positional2") 138 .map(|v| v.as_str()) 139 .unwrap() 140 ) 141 .unwrap(); 142 } else { 143 writeln!(w, "flag2 NOT present").unwrap(); 144 writeln!( 145 w, 146 "option2 maybe present with value of: {}", 147 matches 148 .get_one::<String>("long-option-2") 149 .map(|v| v.as_str()) 150 .unwrap_or("Nothing") 151 ) 152 .unwrap(); 153 writeln!( 154 w, 155 "positional2 maybe present with value of: {}", 156 matches 157 .get_one::<String>("positional2") 158 .map(|v| v.as_str()) 159 .unwrap_or("Nothing") 160 ) 161 .unwrap(); 162 } 163 164 let _ = match matches 165 .get_one::<String>("option3") 166 .map(|v| v.as_str()) 167 .unwrap_or("") 168 { 169 "fast" => writeln!(w, "option3 present quickly"), 170 "slow" => writeln!(w, "option3 present slowly"), 171 _ => writeln!(w, "option3 NOT present"), 172 }; 173 174 let _ = match matches 175 .get_one::<String>("positional3") 176 .map(|v| v.as_str()) 177 .unwrap_or("") 178 { 179 "vi" => writeln!(w, "positional3 present in vi mode"), 180 "emacs" => writeln!(w, "positional3 present in emacs mode"), 181 _ => writeln!(w, "positional3 NOT present"), 182 }; 183 184 if matches.contains_id("option") { 185 if let Some(v) = matches.get_one::<String>("option").map(|v| v.as_str()) { 186 writeln!(w, "option present with value: {}", v).unwrap(); 187 } 188 if let Some(ov) = matches.get_many::<String>("option") { 189 for o in ov { 190 writeln!(w, "An option: {}", o).unwrap(); 191 } 192 } 193 } else { 194 writeln!(w, "option NOT present").unwrap(); 195 } 196 197 if let Some(p) = matches.get_one::<String>("positional").map(|v| v.as_str()) { 198 writeln!(w, "positional present with value: {p}").unwrap(); 199 } else { 200 writeln!(w, "positional NOT present").unwrap(); 201 } 202 if let Some("subcmd") = matches.subcommand_name() { 203 writeln!(w, "subcmd present").unwrap(); 204 if let Some(matches) = matches.subcommand_matches("subcmd") { 205 match matches.get_one::<u8>("flag").unwrap() { 206 0 => { 207 writeln!(w, "flag NOT present").unwrap(); 208 } 209 n => { 210 writeln!(w, "flag present {n} times").unwrap(); 211 } 212 } 213 214 if matches.contains_id("option") { 215 if let Some(v) = matches.get_one::<String>("option").map(|v| v.as_str()) { 216 writeln!(w, "scoption present with value: {v}").unwrap(); 217 } 218 if let Some(ov) = matches.get_many::<String>("option") { 219 for o in ov { 220 writeln!(w, "An scoption: {o}").unwrap(); 221 } 222 } 223 } else { 224 writeln!(w, "scoption NOT present").unwrap(); 225 } 226 227 if let Some(p) = matches 228 .get_one::<String>("scpositional") 229 .map(|v| v.as_str()) 230 { 231 writeln!(w, "scpositional present with value: {p}").unwrap(); 232 } 233 } 234 } else { 235 writeln!(w, "subcmd NOT present").unwrap(); 236 } 237 238 let res = str::from_utf8(&w).unwrap(); 239 snapbox::assert_eq(out, res); 240} 241 242#[test] 243fn create_app() { 244 let _ = Command::new("test") 245 .version("1.0") 246 .author("kevin") 247 .about("does awesome things") 248 .try_get_matches_from(vec![""]) 249 .unwrap(); 250} 251 252#[test] 253fn add_multiple_arg() { 254 let _ = Command::new("test") 255 .args([Arg::new("test").short('s'), Arg::new("test2").short('l')]) 256 .try_get_matches_from(vec![""]) 257 .unwrap(); 258} 259#[test] 260fn flag_x2_opt() { 261 check_complex_output( 262 "clap-test value -f -f -o some", 263 "flag present 2 times 264option present with value: some 265An option: some 266positional present with value: value 267flag2 NOT present 268option2 maybe present with value of: Nothing 269positional2 maybe present with value of: Nothing 270option3 NOT present 271positional3 NOT present 272option present with value: some 273An option: some 274positional present with value: value 275subcmd NOT present 276", 277 ); 278} 279 280#[test] 281fn long_opt_x2_pos() { 282 check_complex_output("clap-test value --option some --option other", O2P); 283} 284 285#[test] 286fn long_opt_eq_x2_pos() { 287 check_complex_output("clap-test value --option=some --option=other", O2P); 288} 289 290#[test] 291fn short_opt_x2_pos() { 292 check_complex_output("clap-test value -o some -o other", O2P); 293} 294 295#[test] 296fn short_opt_eq_x2_pos() { 297 check_complex_output("clap-test value -o=some -o=other", O2P); 298} 299 300#[test] 301fn short_flag_x2_comb_short_opt_pos() { 302 check_complex_output("clap-test value -ff -o some", F2OP); 303} 304 305#[test] 306fn short_flag_short_opt_pos() { 307 check_complex_output("clap-test value -f -o some", FOP); 308} 309 310#[test] 311fn long_flag_long_opt_pos() { 312 check_complex_output("clap-test value --flag --option some", FOP); 313} 314 315#[test] 316fn long_flag_long_opt_eq_pos() { 317 check_complex_output("clap-test value --flag --option=some", FOP); 318} 319 320#[test] 321fn sc_long_flag_long_opt() { 322 check_complex_output("clap-test subcmd value --flag --option some", SCFOP); 323} 324 325#[test] 326fn sc_long_flag_short_opt_pos() { 327 check_complex_output("clap-test subcmd value --flag -o some", SCFOP); 328} 329 330#[test] 331fn sc_long_flag_long_opt_eq_pos() { 332 check_complex_output("clap-test subcmd value --flag --option=some", SCFOP); 333} 334 335#[test] 336fn sc_short_flag_long_opt_pos() { 337 check_complex_output("clap-test subcmd value -f --option some", SCFOP); 338} 339 340#[test] 341fn sc_short_flag_short_opt_pos() { 342 check_complex_output("clap-test subcmd value -f -o some", SCFOP); 343} 344 345#[test] 346fn sc_short_flag_short_opt_eq_pos() { 347 check_complex_output("clap-test subcmd value -f -o=some", SCFOP); 348} 349 350#[test] 351fn sc_short_flag_long_opt_eq_pos() { 352 check_complex_output("clap-test subcmd value -f --option=some", SCFOP); 353} 354 355#[test] 356fn sc_short_flag_x2_comb_long_opt_pos() { 357 check_complex_output("clap-test subcmd value -ff --option some", SCF2OP); 358} 359 360#[test] 361fn sc_short_flag_x2_comb_short_opt_pos() { 362 check_complex_output("clap-test subcmd value -ff -o some", SCF2OP); 363} 364 365#[test] 366fn sc_short_flag_x2_comb_long_opt_eq_pos() { 367 check_complex_output("clap-test subcmd value -ff --option=some", SCF2OP); 368} 369 370#[test] 371fn sc_short_flag_x2_comb_short_opt_eq_pos() { 372 check_complex_output("clap-test subcmd value -ff -o=some", SCF2OP); 373} 374 375#[test] 376fn sc_long_flag_x2_long_opt_pos() { 377 check_complex_output("clap-test subcmd value --flag --flag --option some", SCF2OP); 378} 379 380#[test] 381fn sc_long_flag_x2_short_opt_pos() { 382 check_complex_output("clap-test subcmd value --flag --flag -o some", SCF2OP); 383} 384 385#[test] 386fn sc_long_flag_x2_short_opt_eq_pos() { 387 check_complex_output("clap-test subcmd value --flag --flag -o=some", SCF2OP); 388} 389 390#[test] 391fn sc_long_flag_x2_long_opt_eq_pos() { 392 check_complex_output("clap-test subcmd value --flag --flag --option=some", SCF2OP); 393} 394 395#[test] 396fn sc_short_flag_x2_long_opt_pos() { 397 check_complex_output("clap-test subcmd value -f -f --option some", SCF2OP); 398} 399 400#[test] 401fn sc_short_flag_x2_short_opt_pos() { 402 check_complex_output("clap-test subcmd value -f -f -o some", SCF2OP); 403} 404 405#[test] 406fn sc_short_flag_x2_short_opt_eq_pos() { 407 check_complex_output("clap-test subcmd value -f -f -o=some", SCF2OP); 408} 409 410#[test] 411fn sc_short_flag_x2_long_opt_eq_pos() { 412 check_complex_output("clap-test subcmd value -f -f --option=some", SCF2OP); 413} 414 415#[test] 416fn mut_arg_all() { 417 let mut cmd = utils::complex_app(); 418 let arg_names = cmd 419 .get_arguments() 420 .map(|a| a.get_id().clone()) 421 .filter(|a| a != "version" && a != "help") 422 .collect::<Vec<_>>(); 423 424 for arg_name in arg_names { 425 cmd = cmd.mut_arg(arg_name, |arg| arg.hide_possible_values(true)); 426 } 427} 428 429#[test] 430fn mut_subcommand_all() { 431 let cmd = utils::complex_app(); 432 433 assert_eq!( 434 cmd.find_subcommand("subcmd") 435 .unwrap() 436 .is_disable_version_flag_set(), 437 false 438 ); 439 let cmd = cmd.mut_subcommand("subcmd", |subcmd| subcmd.disable_version_flag(true)); 440 assert_eq!( 441 cmd.find_subcommand("subcmd") 442 .unwrap() 443 .is_disable_version_flag_set(), 444 true 445 ); 446} 447 448#[test] 449fn mut_subcommand_with_alias_resolve() { 450 let mut cmd = 451 Command::new("foo").subcommand(Command::new("bar").alias("baz").about("test subcmd")); 452 assert_eq!( 453 cmd.find_subcommand("baz") 454 .unwrap() 455 .get_about() 456 .unwrap() 457 .to_string(), 458 "test subcmd" 459 ); 460 461 let true_name = cmd.find_subcommand("baz").unwrap().get_name().to_string(); 462 assert_eq!(true_name, "bar"); 463 464 cmd = cmd.mut_subcommand(&*true_name, |subcmd| subcmd.about("modified about")); 465 assert_eq!( 466 cmd.find_subcommand("baz") 467 .unwrap() 468 .get_about() 469 .unwrap() 470 .to_string(), 471 "modified about" 472 ); 473} 474 475#[test] 476fn issue_3669_command_build_recurses() { 477 let mut cmd = Command::new("ctest").subcommand( 478 Command::new("subcmd").subcommand( 479 Command::new("multi") 480 .about("tests subcommands") 481 .author("Kevin K. <kbknapp@gmail.com>") 482 .version("0.1") 483 .arg(clap::arg!( 484 <FLAG> "tests flags" 485 )), 486 ), 487 ); 488 cmd.build(); 489} 490