1use clap::{Arg, ArgAction, ArgMatches, Command}; 2 3fn occurrences_as_vec_vec<'a>(m: &'a ArgMatches, name: &str) -> Vec<Vec<&'a String>> { 4 m.get_occurrences(name) 5 .unwrap() 6 .map(Iterator::collect) 7 .collect() 8} 9 10#[test] 11fn grouped_value_works() { 12 let m = Command::new("cli") 13 .arg( 14 Arg::new("option") 15 .long("option") 16 .action(ArgAction::Set) 17 .num_args(1..) 18 .action(ArgAction::Append), 19 ) 20 .try_get_matches_from([ 21 "cli", 22 "--option", 23 "fr_FR:mon option 1", 24 "en_US:my option 1", 25 "--option", 26 "fr_FR:mon option 2", 27 "en_US:my option 2", 28 ]) 29 .unwrap(); 30 let grouped_vals = occurrences_as_vec_vec(&m, "option"); 31 assert_eq!( 32 grouped_vals, 33 vec![ 34 vec!["fr_FR:mon option 1", "en_US:my option 1",], 35 vec!["fr_FR:mon option 2", "en_US:my option 2",], 36 ] 37 ); 38} 39 40#[test] 41fn issue_1026() { 42 let m = Command::new("cli") 43 .arg(Arg::new("server").short('s').action(ArgAction::Set)) 44 .arg(Arg::new("user").short('u').action(ArgAction::Set)) 45 .arg( 46 Arg::new("target") 47 .long("target") 48 .action(ArgAction::Set) 49 .num_args(1..) 50 .action(ArgAction::Append), 51 ) 52 .try_get_matches_from([ 53 "backup", "-s", "server", "-u", "user", "--target", "target1", "file1", "file2", 54 "file3", "--target", "target2", "file4", "file5", "file6", "file7", "--target", 55 "target3", "file8", 56 ]) 57 .unwrap(); 58 let grouped_vals = occurrences_as_vec_vec(&m, "target"); 59 assert_eq!( 60 grouped_vals, 61 vec![ 62 vec!["target1", "file1", "file2", "file3"], 63 vec!["target2", "file4", "file5", "file6", "file7",], 64 vec!["target3", "file8"] 65 ] 66 ); 67} 68 69#[test] 70fn grouped_value_long_flag_delimiter() { 71 let m = Command::new("myapp") 72 .arg( 73 Arg::new("option") 74 .long("option") 75 .action(ArgAction::Set) 76 .value_delimiter(',') 77 .num_args(1..) 78 .action(ArgAction::Append), 79 ) 80 .try_get_matches_from(vec![ 81 "myapp", 82 "--option=hmm", 83 "--option=val1,val2,val3", 84 "--option", 85 "alice,bob", 86 ]) 87 .unwrap(); 88 let grouped_vals = occurrences_as_vec_vec(&m, "option"); 89 assert_eq!( 90 grouped_vals, 91 vec![ 92 vec!["hmm"], 93 vec!["val1", "val2", "val3"], 94 vec!["alice", "bob"] 95 ] 96 ); 97} 98 99#[test] 100fn grouped_value_short_flag_delimiter() { 101 let m = Command::new("myapp") 102 .arg( 103 Arg::new("option") 104 .short('o') 105 .action(ArgAction::Set) 106 .value_delimiter(',') 107 .num_args(1..) 108 .action(ArgAction::Append), 109 ) 110 .try_get_matches_from(vec!["myapp", "-o=foo", "-o=val1,val2,val3", "-o=bar"]) 111 .unwrap(); 112 let grouped_vals = occurrences_as_vec_vec(&m, "option"); 113 assert_eq!( 114 grouped_vals, 115 vec![vec!["foo"], vec!["val1", "val2", "val3"], vec!["bar"]] 116 ); 117} 118 119#[test] 120fn grouped_value_positional_arg() { 121 let m = Command::new("multiple_values") 122 .arg( 123 Arg::new("pos") 124 .help("multiple positionals") 125 .action(ArgAction::Set) 126 .num_args(1..), 127 ) 128 .try_get_matches_from(vec![ 129 "myprog", "val1", "val2", "val3", "val4", "val5", "val6", 130 ]) 131 .unwrap(); 132 let grouped_vals = occurrences_as_vec_vec(&m, "pos"); 133 assert_eq!( 134 grouped_vals, 135 vec![vec!["val1", "val2", "val3", "val4", "val5", "val6"]] 136 ); 137} 138 139#[test] 140fn grouped_value_multiple_positional_arg() { 141 let m = Command::new("multiple_values") 142 .arg(Arg::new("pos1").help("multiple positionals")) 143 .arg( 144 Arg::new("pos2") 145 .help("multiple positionals") 146 .action(ArgAction::Set) 147 .num_args(1..), 148 ) 149 .try_get_matches_from(vec![ 150 "myprog", "val1", "val2", "val3", "val4", "val5", "val6", 151 ]) 152 .unwrap(); 153 let grouped_vals = occurrences_as_vec_vec(&m, "pos2"); 154 assert_eq!( 155 grouped_vals, 156 vec![vec!["val2", "val3", "val4", "val5", "val6"]] 157 ); 158} 159 160#[test] 161fn grouped_value_multiple_positional_arg_last_multiple() { 162 let m = Command::new("multiple_values") 163 .arg(Arg::new("pos1").help("multiple positionals")) 164 .arg( 165 Arg::new("pos2") 166 .help("multiple positionals") 167 .action(ArgAction::Set) 168 .num_args(1..) 169 .last(true), 170 ) 171 .try_get_matches_from(vec![ 172 "myprog", "val1", "--", "val2", "val3", "val4", "val5", "val6", 173 ]) 174 .unwrap(); 175 let grouped_vals = occurrences_as_vec_vec(&m, "pos2"); 176 assert_eq!( 177 grouped_vals, 178 vec![vec!["val2", "val3", "val4", "val5", "val6"]] 179 ); 180} 181 182#[test] 183fn grouped_interleaved_positional_values() { 184 let cmd = clap::Command::new("foo") 185 .arg(clap::Arg::new("pos").num_args(1..)) 186 .arg( 187 clap::Arg::new("flag") 188 .short('f') 189 .long("flag") 190 .action(ArgAction::Set) 191 .action(ArgAction::Append), 192 ); 193 194 let m = cmd 195 .try_get_matches_from(["foo", "1", "2", "-f", "a", "3", "-f", "b", "4"]) 196 .unwrap(); 197 198 let pos = occurrences_as_vec_vec(&m, "pos"); 199 assert_eq!(pos, vec![vec!["1", "2"], vec!["3"], vec!["4"]]); 200 201 let flag = occurrences_as_vec_vec(&m, "flag"); 202 assert_eq!(flag, vec![vec!["a"], vec!["b"]]); 203} 204 205#[test] 206fn grouped_interleaved_positional_occurrences() { 207 let cmd = clap::Command::new("foo") 208 .arg(clap::Arg::new("pos").num_args(1..)) 209 .arg( 210 clap::Arg::new("flag") 211 .short('f') 212 .long("flag") 213 .action(ArgAction::Set) 214 .action(ArgAction::Append), 215 ); 216 217 let m = cmd 218 .try_get_matches_from(["foo", "1", "2", "-f", "a", "3", "-f", "b", "4"]) 219 .unwrap(); 220 221 let pos = occurrences_as_vec_vec(&m, "pos"); 222 assert_eq!(pos, vec![vec!["1", "2"], vec!["3"], vec!["4"]]); 223 224 let flag = occurrences_as_vec_vec(&m, "flag"); 225 assert_eq!(flag, vec![vec!["a"], vec!["b"]]); 226} 227 228#[test] 229fn issue_2171() { 230 let schema = Command::new("ripgrep#1701 reproducer") 231 .args_override_self(true) 232 .arg( 233 Arg::new("pretty") 234 .short('p') 235 .long("pretty") 236 .action(ArgAction::SetTrue), 237 ) 238 .arg( 239 Arg::new("search_zip") 240 .short('z') 241 .long("search-zip") 242 .action(ArgAction::SetTrue), 243 ); 244 245 let test_args = [ 246 vec!["reproducer", "-pz", "-p"], 247 vec!["reproducer", "-pzp"], 248 vec!["reproducer", "-zpp"], 249 vec!["reproducer", "-pp", "-z"], 250 vec!["reproducer", "-p", "-p", "-z"], 251 vec!["reproducer", "-p", "-pz"], 252 vec!["reproducer", "-ppz"], 253 ]; 254 255 for argv in test_args { 256 let _ = schema.clone().try_get_matches_from(argv).unwrap(); 257 } 258} 259