1use clap::{Arg, ArgAction, ArgMatches, Command}; 2 3fn 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 23fn get_matches(cmd: Command, argv: &'static str) -> ArgMatches { 24 cmd.try_get_matches_from(argv.split(' ').collect::<Vec<_>>()) 25 .unwrap() 26} 27 28fn get_outer_matches(m: &ArgMatches) -> &ArgMatches { 29 m.subcommand_matches("outer") 30 .expect("could not access outer subcommand") 31} 32 33fn get_inner_matches(m: &ArgMatches) -> &ArgMatches { 34 get_outer_matches(m) 35 .subcommand_matches("inner") 36 .expect("could not access inner subcommand") 37} 38 39fn 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 43fn 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 50fn 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 57fn 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 62fn 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 68fn 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] 75fn 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] 84fn 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] 93fn 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] 102fn 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] 111fn 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] 120fn 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] 129fn 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] 138fn 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] 147fn 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