diff --git a/.gitignore b/.gitignore index 3b23b477..9fabb969 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ # Generated by Cargo /target/ +/clap-test/target/ # Cargo files Cargo.lock diff --git a/.travis.yml b/.travis.yml index 04179cd1..ec6bb18e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,7 +18,6 @@ script: cargo build --verbose --no-default-features && cargo build --verbose --features yaml && cargo test --verbose --features yaml && - make -C clap-tests test && travis-cargo --only nightly build -- --features travis && travis-cargo --only nightly bench && travis-cargo --only stable doc -- --features yaml diff --git a/Cargo.toml b/Cargo.toml index 9e7409da..4660957f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,9 @@ yaml-rust = { version = "~0.3.2", optional = true } clippy = { version = "=0.0.64", optional = true } unicode-width = { version = "~0.1.3", optional = true } +[dev-dependencies] +clap-test = { path = "clap-test/" } + [features] default = ["suggestions", "color", "wrap_help"] suggestions = ["strsim"] diff --git a/README.md b/README.md index 39b6abed..e4533b3d 100644 --- a/README.md +++ b/README.md @@ -486,6 +486,7 @@ The following graphic depicts `clap`s dependency graph (generated using [cargo-g * **Dashed** Line: Optional dependency * **Red** Color: **NOT** included by default (must use cargo `features` to enable) + * **Blue** Color: Dev dependency, only used while developing. ![clap dependencies](clap_dep_graph.png) diff --git a/clap-test/Cargo.toml b/clap-test/Cargo.toml new file mode 100644 index 00000000..2f7e9c86 --- /dev/null +++ b/clap-test/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "clap-test" +version = "0.1.0" +authors = ["Kevin K. "] +description = "functions and macros to assist in testing clap" +license = "MIT" + +[dependencies] +regex = "~0.1.69" +clap = { path = "../" } diff --git a/clap-test/src/lib.rs b/clap-test/src/lib.rs new file mode 100644 index 00000000..369784f8 --- /dev/null +++ b/clap-test/src/lib.rs @@ -0,0 +1,164 @@ +extern crate clap; +extern crate regex; + +use std::str; +use std::io::Write; + +use regex::Regex; + +use clap::{App, Arg, SubCommand}; + +pub fn check_err_output(a: App, args: &str, out: &str, use_stderr: bool) { + let res = a.get_matches_from_safe(args.split(' ').collect::>()); + let re = Regex::new("\x1b[^m]*m").unwrap(); + + let mut w = vec![]; + let err = res.unwrap_err(); + err.write_to(&mut w).unwrap(); + let err_s = str::from_utf8(&w).unwrap(); + assert_eq!(re.replace_all(err_s, ""), out); + assert_eq!(use_stderr, err.use_stderr()); +} + +pub fn check_help(mut a: App, out: &str) { + // We call a get_matches method to cause --help and --version to be built + let _ = a.get_matches_from_safe_borrow(vec![""]); + + // Now we check the output of print_help() + let mut help = vec![]; + a.write_help(&mut help).ok().expect("failed to print help"); + assert_eq!(str::from_utf8(&help).unwrap(), out); +} + +pub fn complex_app() -> App<'static, 'static> { + let args = "-o --option=[opt]... 'tests options' + [positional] 'tests positionals'"; + let opt3_vals = ["fast", "slow"]; + let pos3_vals = ["vi", "emacs"]; + App::new("clap-test") + .version("v1.4.8") + .about("tests clap library") + .author("Kevin K. ") + .args_from_usage(args) + .arg(Arg::from_usage("-f --flag... 'tests flags'") + .global(true)) + .args(&[ + Arg::from_usage("[flag2] -F 'tests flags with exclusions'").conflicts_with("flag").requires("long-option-2"), + Arg::from_usage("--long-option-2 [option2] 'tests long options with exclusions'").conflicts_with("option").requires("positional2"), + Arg::from_usage("[positional2] 'tests positionals with exclusions'"), + Arg::from_usage("-O --Option [option3] 'specific vals'").possible_values(&opt3_vals), + Arg::from_usage("[positional3]... 'tests specific values'").possible_values(&pos3_vals), + Arg::from_usage("--multvals [one] [two] 'Tests mutliple values, not mult occs'"), + Arg::from_usage("--multvalsmo... [one] [two] 'Tests mutliple values, and mult occs'"), + Arg::from_usage("--minvals2 [minvals]... 'Tests 2 min vals'").min_values(2), + Arg::from_usage("--maxvals3 [maxvals]... 'Tests 3 max vals'").max_values(3) + ]) + .subcommand(SubCommand::with_name("subcmd") + .about("tests subcommands") + .version("0.1") + .author("Kevin K. ") + .arg_from_usage("-o --option [scoption]... 'tests options'") + .arg_from_usage("[scpositional] 'tests positionals'")) +} + +pub fn check_complex_output(args: &str, out: &str) { + let mut w = vec![]; + let matches = complex_app().get_matches_from(args.split(' ').collect::>()); + if matches.is_present("flag") { + writeln!(w, "flag present {} times", matches.occurrences_of("flag")).unwrap(); + } else { + writeln!(w, "flag NOT present").unwrap(); + } + + if matches.is_present("option") { + if let Some(v) = matches.value_of("option") { + writeln!(w, "option present {} times with value: {}",matches.occurrences_of("option"), v).unwrap(); + } + if let Some(ov) = matches.values_of("option") { + for o in ov { + writeln!(w, "An option: {}", o).unwrap(); + } + } + } else { + writeln!(w, "option NOT present").unwrap(); + } + + if let Some(p) = matches.value_of("positional") { + writeln!(w, "positional present with value: {}", p).unwrap(); + } else { + writeln!(w, "positional NOT present").unwrap(); + } + + if matches.is_present("flag2") { + writeln!(w, "flag2 present").unwrap(); + writeln!(w, "option2 present with value of: {}", matches.value_of("long-option-2").unwrap()).unwrap(); + writeln!(w, "positional2 present with value of: {}", matches.value_of("positional2").unwrap()).unwrap(); + } else { + writeln!(w, "flag2 NOT present").unwrap(); + writeln!(w, "option2 maybe present with value of: {}", matches.value_of("long-option-2").unwrap_or("Nothing")).unwrap(); + writeln!(w, "positional2 maybe present with value of: {}", matches.value_of("positional2").unwrap_or("Nothing")).unwrap(); + } + + let _ = match matches.value_of("Option3").unwrap_or("") { + "fast" => writeln!(w, "option3 present quickly"), + "slow" => writeln!(w, "option3 present slowly"), + _ => writeln!(w, "option3 NOT present") + }; + + let _ = match matches.value_of("positional3").unwrap_or("") { + "vi" => writeln!(w, "positional3 present in vi mode"), + "emacs" => writeln!(w, "positional3 present in emacs mode"), + _ => writeln!(w, "positional3 NOT present") + }; + + if matches.is_present("option") { + if let Some(v) = matches.value_of("option") { + writeln!(w, "option present {} times with value: {}",matches.occurrences_of("option"), v).unwrap(); + } + if let Some(ov) = matches.values_of("option") { + for o in ov { + writeln!(w, "An option: {}", o).unwrap(); + } + } + } else { + writeln!(w, "option NOT present").unwrap(); + } + + if let Some(p) = matches.value_of("positional") { + writeln!(w, "positional present with value: {}", p).unwrap(); + } else { + writeln!(w, "positional NOT present").unwrap(); + } + if matches.is_present("subcmd") { + writeln!(w, "subcmd present").unwrap(); + if let Some(matches) = matches.subcommand_matches("subcmd") { + if matches.is_present("flag") { + writeln!(w, "flag present {} times", matches.occurrences_of("flag")).unwrap(); + } else { + writeln!(w, "flag NOT present").unwrap(); + } + + if matches.is_present("option") { + if let Some(v) = matches.value_of("option") { + writeln!(w, "scoption present with value: {}", v).unwrap(); + } + if let Some(ov) = matches.values_of("option") { + for o in ov { + writeln!(w, "An scoption: {}", o).unwrap(); + } + } + } else { + writeln!(w, "scoption NOT present").unwrap(); + } + + if let Some(p) = matches.value_of("scpositional") { + writeln!(w, "scpositional present with value: {}", p).unwrap(); + } + } + } else { + writeln!(w, "subcmd NOT present").unwrap(); + } + + let res = str::from_utf8(&w).unwrap(); + assert_eq!(res, out); +} diff --git a/clap-tests/.gitignore b/clap-tests/.gitignore deleted file mode 100644 index 37727f91..00000000 --- a/clap-tests/.gitignore +++ /dev/null @@ -1,11 +0,0 @@ -# Compiled files -*.o -*.so -*.rlib -*.dll - -# Executables -*.exe - -# Generated by Cargo -/target/ diff --git a/clap-tests/Cargo.toml b/clap-tests/Cargo.toml deleted file mode 100644 index c7d21802..00000000 --- a/clap-tests/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] - -name = "claptests" -version = "0.0.1" -authors = ["Kevin K. "] - -[dependencies.clap] -path = ".." diff --git a/clap-tests/Makefile b/clap-tests/Makefile deleted file mode 100644 index 6c7a7af6..00000000 --- a/clap-tests/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -.PHONY: build test clean - -build: - @# It may be that this project was never built, and no Cargo.lock exists. - @# Thus it may be ignored - cargo update 2>/dev/null || : - cargo build --release - -test: - $(MAKE) build || ($(MAKE) clean && false) - ./run_tests.py - -clean: - cargo clean diff --git a/clap-tests/run_tests.py b/clap-tests/run_tests.py deleted file mode 100755 index 356609e4..00000000 --- a/clap-tests/run_tests.py +++ /dev/null @@ -1,264 +0,0 @@ -#!/usr/bin/env python -import sys -import subprocess -import re -import difflib - -failed = False - -_ansi = re.compile(r'\x1b[^m]*m') - -_help = '''claptests v1.4.8 -Kevin K. -tests clap library - -USAGE: - claptests [FLAGS] [OPTIONS] [ARGS] [SUBCOMMAND] - -FLAGS: - -f, --flag tests flags - -F tests flags with exclusions - -h, --help Prints help information - -V, --version Prints version information - -OPTIONS: - -O, --Option tests options with specific value sets [values: fast, slow] - --long-option-2 tests long options with exclusions - --maxvals3 ... Tests 3 max vals - --minvals2 ... Tests 2 min vals - --multvals Tests mutliple values, not mult occs - --multvalsmo Tests mutliple values, and mult occs - -o, --option ... tests options - -ARGS: - [positional] tests positionals - [positional2] tests positionals with exclusions - [positional3]... tests positionals with specific values [values: vi, emacs] - -SUBCOMMANDS: - help Prints this message or the help of the given subcommand(s) - subcmd tests subcommands''' - -_version = "claptests v1.4.8" - -_sc_dym_usage = '''error: The subcommand 'subcm' wasn't recognized -\tDid you mean 'subcmd' ? - -If you believe you received this message in error, try re-running with 'claptests -- subcm' - -USAGE: - claptests [FLAGS] [OPTIONS] [ARGS] [SUBCOMMAND] - -For more information try --help''' - -_arg_dym_usage = '''error: Found argument '--optio' which wasn't expected, or isn't valid in this context -\tDid you mean --option ? - -USAGE: - claptests --option ... - -For more information try --help''' - -_pv_dym_usage = '''error: 'slo' isn't a valid value for '--Option ' -\t[valid values: fast slow] - - Did you mean 'slow' ? - -USAGE: - claptests --Option - -For more information try --help''' - -_excluded = '''error: The argument '--flag' cannot be used with '-F' - -USAGE: - claptests [positional2] -F --long-option-2 - -For more information try --help''' - -_excluded_l = '''error: The argument '-f' cannot be used with '-F' - -USAGE: - claptests [positional2] -F --long-option-2 - -For more information try --help''' - -_required = '''error: The following required arguments were not provided: - [positional2] - --long-option-2 - -USAGE: - claptests [positional2] -F --long-option-2 - -For more information try --help''' - -_fop = '''flag present 1 times -option present 1 times with value: some -An option: some -positional present with value: value -flag2 NOT present -option2 maybe present with value of: Nothing -positional2 maybe present with value of: Nothing -option3 NOT present -positional3 NOT present -option present 1 times with value: some -An option: some -positional present with value: value -subcmd NOT present''' - -_f2op = '''flag present 2 times -option present 1 times with value: some -An option: some -positional present with value: value -flag2 NOT present -option2 maybe present with value of: Nothing -positional2 maybe present with value of: Nothing -option3 NOT present -positional3 NOT present -option present 1 times with value: some -An option: some -positional present with value: value -subcmd NOT present''' - -_o2p = '''flag NOT present -option present 2 times with value: some -An option: some -An option: other -positional present with value: value -flag2 NOT present -option2 maybe present with value of: Nothing -positional2 maybe present with value of: Nothing -option3 NOT present -positional3 NOT present -option present 2 times with value: some -An option: some -An option: other -positional present with value: value -subcmd NOT present''' - -_schelp = '''claptests-subcmd 0.1 -Kevin K. -tests subcommands - -USAGE: - claptests subcmd [FLAGS] [OPTIONS] [--] [ARGS] - -FLAGS: - -f, --flag tests flags - -h, --help Prints help information - -V, --version Prints version information - -OPTIONS: - -o, --option ... tests options - -ARGS: - [scpositional] tests positionals''' - -_scfop = '''flag NOT present -option NOT present -positional NOT present -flag2 NOT present -option2 maybe present with value of: Nothing -positional2 maybe present with value of: Nothing -option3 NOT present -positional3 NOT present -option NOT present -positional NOT present -subcmd present -flag present 1 times -scoption present with value: some -An scoption: some -scpositional present with value: value''' - -_scf2op = '''flag NOT present -option NOT present -positional NOT present -flag2 NOT present -option2 maybe present with value of: Nothing -positional2 maybe present with value of: Nothing -option3 NOT present -positional3 NOT present -option NOT present -positional NOT present -subcmd present -flag present 2 times -scoption present with value: some -An scoption: some -scpositional present with value: value''' - -_bin = './target/release/claptests' - -cmds = {'help short: ': ['{} -h'.format(_bin), _help, 0], - 'help long: ': ['{} --help'.format(_bin), _help, 0], - 'version short: ': ['{} -V'.format(_bin), _version, 0], - 'version long: ': ['{} --version'.format(_bin), _version, 0], - 'help subcmd: ': ['{} help'.format(_bin), _help, 0], - 'missing required: ': ['{} -F'.format(_bin), _required, 1], - 'F2(ss),O(s),P: ': ['{} value -f -f -o some'.format(_bin), _f2op, 0], - 'arg dym: ': ['{} --optio=foo'.format(_bin), _arg_dym_usage, 1], - 'O2(ll)P: ': ['{} value --option some --option other'.format(_bin), _o2p, 0], - 'O2(l=l=)P: ': ['{} value --option=some --option=other'.format(_bin), _o2p, 0], - 'O2(ss)P: ': ['{} value -o some -o other'.format(_bin), _o2p, 0], - 'F2(s2),O(s),P: ': ['{} value -ff -o some'.format(_bin), _f2op, 0], - 'F(s),O(s),P: ': ['{} value -f -o some'.format(_bin), _fop, 0], - 'F(l),O(l),P: ': ['{} value --flag --option some'.format(_bin), _fop, 0], - 'F(l),O(l=),P: ': ['{} value --flag --option=some'.format(_bin), _fop, 0], - 'sc dym: ': ['{} subcm'.format(_bin), _sc_dym_usage, 1], - 'sc help short: ': ['{} subcmd -h'.format(_bin), _schelp, 0], - 'sc help long: ': ['{} subcmd --help'.format(_bin), _schelp, 0], - 'scF(l),O(l),P: ': ['{} subcmd value --flag --option some'.format(_bin), _scfop, 0], - 'scF(l),O(s),P: ': ['{} subcmd value --flag -o some'.format(_bin), _scfop, 0], - 'scF(l),O(l=),P: ': ['{} subcmd value --flag --option=some'.format(_bin), _scfop, 0], - 'scF(s),O(l),P: ': ['{} subcmd value -f --option some'.format(_bin), _scfop, 0], - 'scF(s),O(s),P: ': ['{} subcmd value -f -o some'.format(_bin), _scfop, 0], - 'scF(s),O(l=),P: ': ['{} subcmd value -f --option=some'.format(_bin), _scfop, 0], - 'scF2(s),O(l),P: ': ['{} subcmd value -ff --option some'.format(_bin), _scf2op, 0], - 'scF2(s),O(s),P: ': ['{} subcmd value -ff -o some'.format(_bin), _scf2op, 0], - 'scF2(s),O(l=),P: ': ['{} subcmd value -ff --option=some'.format(_bin), _scf2op, 0], - 'scF2(l2),O(l),P: ': ['{} subcmd value --flag --flag --option some'.format(_bin), _scf2op, 0], - 'scF2(l2),O(s),P: ': ['{} subcmd value --flag --flag -o some'.format(_bin), _scf2op, 0], - 'scF2(l2),O(l=),P: ': ['{} subcmd value --flag --flag --option=some'.format(_bin), _scf2op, 0], - 'scF2(s2),O(l),P: ': ['{} subcmd value -f -f --option some'.format(_bin), _scf2op, 0], - 'scF2(s2),O(s),P: ': ['{} subcmd value -f -f -o some'.format(_bin), _scf2op, 0], - 'scF2(s2),O(l=),P: ': ['{} subcmd value -f -f --option=some'.format(_bin), _scf2op, 0] - } - -def pass_fail(name, cmd, check, good): - sys.stdout.write(name) - if check == good: - print('Pass') - return 0 - print('Fail') - print('\n\n{}\n# Should be:\n$ {}\n{}\n\n{}\n# But is:\n$ {}\n{}\n\n'.format('#'*25, cmd, good, '#'*25, cmd, check)) - for line in difflib.context_diff(good.splitlines(), check.splitlines(), fromfile="Should Be", tofile="Currently Is", lineterm=""): - print(line) - print() - return 1 - - -def main(): - num_failed = 0 - total = len(cmds) - for cmd, cmd_v in cmds.items(): - proc = subprocess.Popen(cmd_v[0], shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) - out, err = proc.communicate() - out = _ansi.sub('', out.strip()) - err = _ansi.sub('', err.strip()) - rc = proc.returncode - if rc != cmd_v[-1]: - print('{}Fail (Exit Code={}; Should be={})'.format(cmd, rc, cmd_v[-1])) - num_failed += 1 - continue - if out and rc == cmd_v[-1]: - num_failed += pass_fail(cmd, cmd_v[0], out, cmd_v[1]) - elif rc == cmd_v[-1]: - num_failed += pass_fail(cmd, cmd_v[0], err, cmd_v[1]) - - print() - if num_failed: - print('{}/{} tests failed'.format(num_failed, total)) - return 1 - print('{}/{} tests passed!'.format(total, total)) - -if __name__ == '__main__': - sys.exit(main()) diff --git a/clap-tests/src/main.rs b/clap-tests/src/main.rs deleted file mode 100644 index ba7e72c9..00000000 --- a/clap-tests/src/main.rs +++ /dev/null @@ -1,132 +0,0 @@ -#[macro_use] -extern crate clap; - -use clap::{App, Arg, SubCommand}; - - -fn main() { - let args = "-o --option=[opt]... 'tests options' - [positional] 'tests positionals'"; - let opt3_vals = ["fast", "slow"]; - let pos3_vals = ["vi", "emacs"]; - let matches = App::new("claptests") - .version("v1.4.8") - .about("tests clap library") - .author("Kevin K. ") - .args_from_usage(args) - .arg(Arg::from_usage("-f --flag... 'tests flags'") - .global(true)) - .args(&[ - Arg::from_usage("[flag2] -F 'tests flags with exclusions'").conflicts_with("flag").requires("long-option-2"), - Arg::from_usage("--long-option-2 [option2] 'tests long options with exclusions'").conflicts_with("option").requires("positional2"), - Arg::from_usage("[positional2] 'tests positionals with exclusions'"), - Arg::from_usage("-O --Option [option3] 'tests options with specific value sets'").possible_values(&opt3_vals), - Arg::from_usage("[positional3]... 'tests positionals with specific values'").possible_values(&pos3_vals), - Arg::from_usage("--multvals [one] [two] 'Tests mutliple values, not mult occs'"), - Arg::from_usage("--multvalsmo... [one] [two] 'Tests mutliple values, and mult occs'"), - Arg::from_usage("--minvals2 [minvals]... 'Tests 2 min vals'").min_values(2), - Arg::from_usage("--maxvals3 [maxvals]... 'Tests 3 max vals'").max_values(3) - ]) - .subcommand(SubCommand::with_name("subcmd") - .about("tests subcommands") - .version("0.1") - .author("Kevin K. ") - .arg_from_usage("-o --option [scoption]... 'tests options'") - .arg_from_usage("[scpositional] 'tests positionals'")) - .get_matches(); - - if matches.is_present("flag") { - println!("flag present {} times", matches.occurrences_of("flag")); - } else { - println!("flag NOT present"); - } - - if matches.is_present("option") { - if let Some(v) = matches.value_of("option") { - println!("option present {} times with value: {}",matches.occurrences_of("option"), v); - } - if let Some(ov) = matches.values_of("option") { - for o in ov { - println!("An option: {}", o); - } - } - } else { - println!("option NOT present"); - } - - if let Some(p) = matches.value_of("positional") { - println!("positional present with value: {}", p); - } else { - println!("positional NOT present"); - } - - if matches.is_present("flag2") { - println!("flag2 present"); - println!("option2 present with value of: {}", matches.value_of("long-option-2").unwrap()); - println!("positional2 present with value of: {}", matches.value_of("positional2").unwrap()); - } else { - println!("flag2 NOT present"); - println!("option2 maybe present with value of: {}", matches.value_of("long-option-2").unwrap_or("Nothing")); - println!("positional2 maybe present with value of: {}", matches.value_of("positional2").unwrap_or("Nothing")); - } - - match matches.value_of("Option3").unwrap_or("") { - "fast" => println!("option3 present quickly"), - "slow" => println!("option3 present slowly"), - _ => println!("option3 NOT present") - } - - match matches.value_of("positional3").unwrap_or("") { - "vi" => println!("positional3 present in vi mode"), - "emacs" => println!("positional3 present in emacs mode"), - _ => println!("positional3 NOT present") - } - - if matches.is_present("option") { - if let Some(v) = matches.value_of("option") { - println!("option present {} times with value: {}",matches.occurrences_of("option"), v); - } - if let Some(ov) = matches.values_of("option") { - for o in ov { - println!("An option: {}", o); - } - } - } else { - println!("option NOT present"); - } - - if let Some(p) = matches.value_of("positional") { - println!("positional present with value: {}", p); - } else { - println!("positional NOT present"); - } - if matches.is_present("subcmd") { - println!("subcmd present"); - if let Some(matches) = matches.subcommand_matches("subcmd") { - if matches.is_present("flag") { - println!("flag present {} times", matches.occurrences_of("flag")); - } else { - println!("flag NOT present"); - } - - if matches.is_present("option") { - if let Some(v) = matches.value_of("option") { - println!("scoption present with value: {}", v); - } - if let Some(ov) = matches.values_of("option") { - for o in ov { - println!("An scoption: {}", o); - } - } - } else { - println!("scoption NOT present"); - } - - if let Some(p) = matches.value_of("scpositional") { - println!("scpositional present with value: {}", p); - } - } - } else { - println!("subcmd NOT present"); - } -} diff --git a/clap_dep_graph.dot b/clap_dep_graph.dot new file mode 100644 index 00000000..30475083 --- /dev/null +++ b/clap_dep_graph.dot @@ -0,0 +1,58 @@ +digraph dependencies { + N0[label="clap"]; + N1[label="ansi_term",style=dashed]; + N2[label="bitflags"]; + N3[label="clippy",color=blue,style=dashed]; + N4[label="libc",style=dashed]; + N5[label="strsim",style=dashed]; + N6[label="unicode-width",style=dashed]; + N7[label="vec_map"]; + N8[label="yaml-rust",style=dashed,color=red]; + N9[label="clap-test",style=dashed,color=blue]; + N10[label="aho-corasick",color=blue,style=dashed]; + N11[label="memchr",color=blue,style=dashed]; + N12[label="regex",color=blue,style=dashed]; + N13[label="quine-mc_cluskey",color=blue,style=dashed]; + N14[label="regex-syntax",color=blue,style=dashed]; + N15[label="semver",color=blue,style=dashed]; + N16[label="toml",color=blue,style=dashed]; + N17[label="unicode-normalization",color=blue,style=dashed]; + N18[label="kernel32-sys",color=blue,style=dashed]; + N19[label="winapi",color=blue,style=dashed]; + N20[label="winapi-build",color=blue,style=dashed]; + N21[label="nom",color=blue,style=dashed]; + N22[label="thread_local",color=blue,style=dashed]; + N23[label="utf8-ranges",color=blue,style=dashed]; + N24[label="rustc-serialize",color=blue,style=dashed]; + N25[label="thread-id"color=blue,style=dashed]; + N0 -> N1[label="",style=dashed]; + N0 -> N2[label=""]; + N0 -> N3[label="",style=dashed,color=blue]; + N0 -> N4[label="",style=dashed]; + N0 -> N5[label="",style=dashed]; + N0 -> N6[label="",style=dashed]; + N0 -> N7[label=""]; + N0 -> N8[label="",style=dashed,color=red]; + N0 -> N9[label="",style=dashed,color=blue]; + N3 -> N13[label="",style=dashed,color=blue]; + N3 -> N14[label="",style=dashed,color=blue]; + N3 -> N15[label="",style=dashed,color=blue]; + N3 -> N16[label="",style=dashed,color=blue]; + N3 -> N17[label="",style=dashed,color=blue]; + N9 -> N0[label="",style=dashed,color=blue]; + N9 -> N12[label="",style=dashed,color=blue]; + N10 -> N11[label="",style=dashed,color=blue]; + N11 -> N4[label="",style=dashed,color=blue]; + N12 -> N10[label="",style=dashed,color=blue]; + N12 -> N11[label="",style=dashed,color=blue]; + N12 -> N14[label="",style=dashed,color=blue]; + N12 -> N22[label="",style=dashed,color=blue]; + N12 -> N23[label="",style=dashed,color=blue]; + N15 -> N21[label="",style=dashed,color=blue]; + N16 -> N24[label="",style=dashed,color=blue]; + N18 -> N19[label="",style=dashed,color=blue]; + N18 -> N20[label="",style=dashed,color=blue]; + N22 -> N25[label="",style=dashed,color=blue]; + N25 -> N4[label="",style=dashed,color=blue]; + N25 -> N18[label="",style=dashed,color=blue]; +} diff --git a/clap_dep_graph.png b/clap_dep_graph.png index 18d3d44d..2d3dcc1d 100644 Binary files a/clap_dep_graph.png and b/clap_dep_graph.png differ diff --git a/src/app/macros.rs b/src/app/macros.rs index f52b91b6..56b612f0 100644 --- a/src/app/macros.rs +++ b/src/app/macros.rs @@ -77,21 +77,19 @@ macro_rules! _handle_group_reqs{ debugln!("macro=_handle_group_reqs!;"); for grp in $me.groups.values() { let mut found = false; - for name in &grp.args { - if name == &$arg.name() { - vec_remove!($me.required, name); - if let Some(ref reqs) = grp.requires { - $me.required.extend(reqs); - } - if let Some(ref bl) = grp.conflicts { - $me.blacklist.extend(bl); - } - found = true; // What if arg is in more than one group with different reqs? - break; + if grp.args.contains(&$arg.name()) { + vec_remove!($me.required, &$arg.name()); + if let Some(ref reqs) = grp.requires { + $me.required.extend(reqs); } + if let Some(ref bl) = grp.conflicts { + $me.blacklist.extend(bl); + } + found = true; // What if arg is in more than one group with different reqs? } if found { vec_remove_all!($me.required, &grp.args); + debugln!("Adding args from group to blacklist...{:?}", grp.args); $me.blacklist.extend(&grp.args); vec_remove!($me.blacklist, &$arg.name()); } diff --git a/src/app/parser.rs b/src/app/parser.rs index 95170a0c..e369a7c3 100644 --- a/src/app/parser.rs +++ b/src/app/parser.rs @@ -296,6 +296,16 @@ impl<'a, 'b> Parser<'a, 'b> grps, tmp }); let mut ret_val = VecDeque::new(); + c_pos.dedup(); + c_flags.dedup(); + c_opt.dedup(); + grps.dedup(); + let mut args_in_groups = vec![]; + for g in grps.iter() { + for a in self.arg_names_in_group(g).into_iter() { + args_in_groups.push(a); + } + } let mut pmap = BTreeMap::new(); for p in c_pos.into_iter() { @@ -303,10 +313,19 @@ impl<'a, 'b> Parser<'a, 'b> continue; } if let Some(p) = self.positionals.values().filter(|x| &x.name == &p).next() { + if args_in_groups.contains(&p.name) { + continue; + } pmap.insert(p.index, p.to_string()); } } + debugln!("args_in_groups={:?}", args_in_groups); for (_, s) in pmap { + if !args_in_groups.is_empty() { + if args_in_groups.contains(&&*s) { + continue; + } + } ret_val.push_back(s); } macro_rules! write_arg { @@ -321,10 +340,15 @@ impl<'a, 'b> Parser<'a, 'b> } write_arg!(self.flags.iter(), matcher, c_flags, ret_val); write_arg!(self.opts.iter(), matcher, c_opt, ret_val); + let mut g_vec = vec![]; for g in grps.into_iter() { let g_string = self.args_in_group(g) .join("|"); - ret_val.push_back(format!("[{}]", &g_string[..g_string.len()])); + g_vec.push(format!("<{}>", &g_string[..g_string.len()])); + } + g_vec.dedup(); + for g in g_vec.into_iter() { + ret_val.push_back(g); } ret_val @@ -683,7 +707,7 @@ impl<'a, 'b> Parser<'a, 'b> if let Some(pos) = self.positionals.values().filter(|p| &p.name == &k).next() { if let Some(ref bl) = pos.blacklist { if bl.contains(&name) { - return Some(pos.to_string()); + return Some(pos.name.to_owned()); } } } @@ -757,7 +781,7 @@ impl<'a, 'b> Parser<'a, 'b> .values() .filter(|p| &p.name == n) .next() { - args.push(p.to_string()); + args.push(p.name.to_owned()); } } @@ -1156,6 +1180,7 @@ impl<'a, 'b> Parser<'a, 'b> debugln!("macro=build_err;"); let c_with = $me.blacklisted_from($name, &$matcher); debugln!("'{:?}' conflicts with '{}'", c_with, $name); + $matcher.remove($name); let usg = $me.create_current_usage($matcher); if let Some(f) = $me.flags.iter().filter(|f| f.name == $name).next() { debugln!("It was a flag..."); diff --git a/src/args/arg_builder/positional.rs b/src/args/arg_builder/positional.rs index 69d71203..5a265991 100644 --- a/src/args/arg_builder/positional.rs +++ b/src/args/arg_builder/positional.rs @@ -112,28 +112,15 @@ impl<'n, 'e> PosBuilder<'n, 'e> { impl<'n, 'e> Display for PosBuilder<'n, 'e> { fn fmt(&self, f: &mut Formatter) -> Result { - if self.settings.is_set(ArgSettings::Required) { - if let Some(ref names) = self.val_names { - try!(write!(f, - "{}", - names.values() - .map(|n| format!("<{}>", n)) - .collect::>() - .join(" "))); - } else { - try!(write!(f, "<{}>", self.name)); - } + if let Some(ref names) = self.val_names { + try!(write!(f, + "{}", + names.values() + .map(|n| format!("<{}>", n)) + .collect::>() + .join(" "))); } else { - if let Some(ref names) = self.val_names { - try!(write!(f, - "{}", - names.values() - .map(|n| format!("[{}]", n)) - .collect::>() - .join(" "))); - } else { - try!(write!(f, "[{}]", self.name)); - } + try!(write!(f, "<{}>", self.name)); } if self.settings.is_set(ArgSettings::Multiple) && self.val_names.is_none() { try!(write!(f, "...")); @@ -250,7 +237,7 @@ mod test { let mut p = PosBuilder::new("pos", 1); p.settings.set(ArgSettings::Multiple); - assert_eq!(&*format!("{}", p), "[pos]..."); + assert_eq!(&*format!("{}", p), "..."); } #[test] @@ -269,7 +256,7 @@ mod test { vm.insert(1, "file2"); p2.val_names = Some(vm); - assert_eq!(&*format!("{}", p2), "[file1] [file2]"); + assert_eq!(&*format!("{}", p2), " "); } #[test] diff --git a/src/errors.rs b/src/errors.rs index ef1ae7df..dc33c597 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -354,6 +354,11 @@ impl Error { process::exit(0); } + #[doc(hidden)] + pub fn write_to(&self, w: &mut W) -> io::Result<()> { + write!(w, "{}", self.message) + } + #[doc(hidden)] pub fn argument_conflict<'a, 'b, A, O, U>(arg: &A, other: Option, usage: U) -> Self where A: AnyArg<'a, 'b> + Display, diff --git a/tests/app_settings.rs b/tests/app_settings.rs index 124832c2..54df0c15 100644 --- a/tests/app_settings.rs +++ b/tests/app_settings.rs @@ -102,7 +102,7 @@ OPTIONS: -V, --version Prints version information ARGS: - [arg1] some pos arg\n")); + some pos arg\n")); } #[test] @@ -135,5 +135,5 @@ OPTIONS: -o, --opt some option ARGS: - [arg1] some pos arg\n")); + some pos arg\n")); } diff --git a/tests/conflicts.rs b/tests/conflicts.rs index 40117a1a..b9398bd1 100644 --- a/tests/conflicts.rs +++ b/tests/conflicts.rs @@ -1,7 +1,22 @@ +extern crate clap_test; extern crate clap; use clap::{App, Arg, ErrorKind, ArgGroup}; +static CONFLICT_ERR: &'static str = "error: The argument '--flag' cannot be used with '-F' + +USAGE: + clap-test -F --long-option-2 + +For more information try --help"; + +static CONFLICT_ERR_REV: &'static str = "error: The argument '--flag' cannot be used with '-F' + +USAGE: + clap-test -F --long-option-2 + +For more information try --help"; + #[test] fn flag_conflict() { let result = App::new("flag_conflict") @@ -59,3 +74,13 @@ fn group_conflict_2() { let err = result.err().unwrap(); assert_eq!(err.kind, ErrorKind::ArgumentConflict); } + +#[test] +fn conflict_output() { + clap_test::check_err_output(clap_test::complex_app(), "clap-test val1 --flag --long-option-2 val2 -F", CONFLICT_ERR, true); +} + +#[test] +fn conflict_output_rev() { + clap_test::check_err_output(clap_test::complex_app(), "clap-test val1 -F --long-option-2 val2 --flag", CONFLICT_ERR_REV, true); +} diff --git a/tests/groups.rs b/tests/groups.rs index eeaa4201..351839b2 100644 --- a/tests/groups.rs +++ b/tests/groups.rs @@ -1,4 +1,5 @@ extern crate clap; +extern crate clap_test; use clap::{App, Arg, ArgGroup, ErrorKind}; @@ -89,3 +90,61 @@ fn empty_group() { let err = r.err().unwrap(); assert_eq!(err.kind, ErrorKind::MissingRequiredArgument); } + +#[test] +fn req_group_usage_string() { + let app = App::new("req_group") + .args_from_usage("[base] 'Base commit' + -d, --delete 'Remove the base commit information'") + .group(ArgGroup::with_name("base_or_delete") + .args(&["base", "delete"]) + .required(true)); + + clap_test::check_err_output(app, "clap-test", +"error: The following required arguments were not provided: + + +USAGE: + clap-test [FLAGS] [ARGS] + +For more information try --help", true); + +} + +#[test] +fn req_group_with_conflict_usage_string() { + let app = App::new("req_group") + .arg(Arg::from_usage("[base] 'Base commit'").conflicts_with("delete")) + .arg(Arg::from_usage("-d, --delete 'Remove the base commit information'")) + .group(ArgGroup::with_name("base_or_delete") + .args(&["base", "delete"]) + .required(true)); + + clap_test::check_err_output(app, "clap-test --delete base", +"error: The argument '--delete' cannot be used with 'base' + +USAGE: + clap-test + +For more information try --help", true); + +} + +#[test] +fn req_group_with_conflict_rev_usage_string() { + let app = App::new("req_group") + .arg(Arg::from_usage("[base] 'Base commit'").conflicts_with("delete")) + .arg(Arg::from_usage("-d, --delete 'Remove the base commit information'")) + .group(ArgGroup::with_name("base_or_delete") + .args(&["base", "delete"]) + .required(true)); + + clap_test::check_err_output(app, "clap-test --delete base", +"error: The argument '--delete' cannot be used with 'base' + +USAGE: + clap-test + +For more information try --help", true); + +} diff --git a/tests/help.rs b/tests/help.rs index e46250a6..cf866c06 100644 --- a/tests/help.rs +++ b/tests/help.rs @@ -1,6 +1,56 @@ +extern crate clap_test; extern crate clap; -use clap::{App, SubCommand, ErrorKind, Arg}; +use clap::{App, SubCommand, ErrorKind}; + +static HELP: &'static str = "clap-test v1.4.8 +Kevin K. +tests clap library + +USAGE: + clap-test [FLAGS] [OPTIONS] [ARGS] [SUBCOMMAND] + +FLAGS: + -f, --flag tests flags + -F tests flags with exclusions + -h, --help Prints help information + -V, --version Prints version information + +OPTIONS: + -O, --Option specific vals [values: fast, slow] + --long-option-2 tests long options with exclusions + --maxvals3 ... Tests 3 max vals + --minvals2 ... Tests 2 min vals + --multvals Tests mutliple values, not mult occs + --multvalsmo Tests mutliple values, and mult occs + -o, --option ... tests options + +ARGS: + tests positionals + tests positionals with exclusions + ... tests specific values [values: vi, emacs] + +SUBCOMMANDS: + help Prints this message or the help of the given subcommand(s) + subcmd tests subcommands +"; + +static SC_HELP: &'static str = "subcmd 0.1 +Kevin K. +tests subcommands + +USAGE: + subcmd [FLAGS] [OPTIONS] [--] [ARGS] + +FLAGS: + -f, --flag tests flags + +OPTIONS: + -o, --option ... tests options + +ARGS: + tests positionals +"; #[test] fn help_short() { @@ -54,69 +104,44 @@ fn help_subcommand() { } #[test] -fn print_app_help() { - let mut app = App::new("test") - .author("Kevin K.") - .about("tests stuff") - .version("1.3") - .args_from_usage("-f, --flag 'some flag' - --option [opt] 'some option'") - .arg(Arg::with_name("other") - .short("O") - .long("other-opt") - .takes_value(true) - .help("some other opt")); - // We call a get_matches method to cause --help and --version to be built - let _ = app.get_matches_from_safe_borrow(vec![""]); +fn subcommand_short_help() { + let m = clap_test::complex_app() + .get_matches_from_safe(vec!["clap-test", "subcmd", "-h"]); - // Now we check the output of print_help() - let mut help = vec![]; - app.write_help(&mut help).ok().expect("failed to print help"); - assert_eq!(&*String::from_utf8_lossy(&*help), &*String::from("test 1.3\n\ -Kevin K. -tests stuff - -USAGE: - test [FLAGS] [OPTIONS] - -FLAGS: - -f, --flag some flag - -h, --help Prints help information - -V, --version Prints version information - -OPTIONS: - --option some option - -O, --other-opt some other opt\n")); + assert!(m.is_err()); + assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed); } #[test] -fn possible_values() { - let mut app = App::new("test") - .author("Kevin K.") - .about("tests stuff") - .version("1.3") - .args(&[Arg::from_usage("-o, --opt [opt] 'some option'").possible_values(&["one", "two"]), - Arg::from_usage("[arg1] 'some pos arg'").possible_values(&["three", "four"])]); - // We call a get_matches method to cause --help and --version to be built - let _ = app.get_matches_from_safe_borrow(vec![""]); +fn subcommand_long_help() { + let m = clap_test::complex_app() + .get_matches_from_safe(vec!["clap-test", "subcmd", "--help"]); + assert!(m.is_err()); + assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed); +} + +#[test] +fn subcommand_help_rev() { + let m = clap_test::complex_app() + .get_matches_from_safe(vec!["clap-test", "help", "subcmd"]); + + assert!(m.is_err()); + assert_eq!(m.unwrap_err().kind, ErrorKind::HelpDisplayed); +} + +#[test] +fn complex_help_output() { + clap_test::check_help(clap_test::complex_app(), HELP); +} + +#[test] +fn complex_subcommand_help_output() { + let mut a = clap_test::complex_app(); + let _ = a.get_matches_from_safe_borrow(vec![""]); + let sc = a.p.subcommands.iter().filter(|s| s.p.meta.name == "subcmd").next().unwrap(); // Now we check the output of print_help() let mut help = vec![]; - app.write_help(&mut help).expect("failed to print help"); - assert_eq!(&*String::from_utf8_lossy(&*help), &*String::from("test 1.3\n\ -Kevin K. -tests stuff - -USAGE: - test [FLAGS] [OPTIONS] [ARGS] - -FLAGS: - -h, --help Prints help information - -V, --version Prints version information - -OPTIONS: - -o, --opt some option [values: one, two] - -ARGS: - [arg1] some pos arg [values: three, four]\n")); + sc.write_help(&mut help).ok().expect("failed to print help"); + assert_eq!(&*String::from_utf8(help).unwrap(), SC_HELP); } diff --git a/tests/opts.rs b/tests/opts.rs index 357ce2e7..c4dffbc9 100644 --- a/tests/opts.rs +++ b/tests/opts.rs @@ -1,3 +1,4 @@ +extern crate clap_test; extern crate clap; use clap::{App, Arg}; @@ -168,3 +169,15 @@ fn default_values_user_value() { assert!(m.is_present("o")); assert_eq!(m.value_of("o").unwrap(), "value"); } + +#[test] +fn did_you_mean() { + clap_test::check_err_output(clap_test::complex_app(), "clap-test --optio=foo", +"error: Found argument '--optio' which wasn't expected, or isn't valid in this context +\tDid you mean --option ? + +USAGE: + clap-test --option ... + +For more information try --help", true); +} diff --git a/tests/possible_values.rs b/tests/possible_values.rs index cf013e04..b07df9aa 100644 --- a/tests/possible_values.rs +++ b/tests/possible_values.rs @@ -1,7 +1,18 @@ +extern crate clap_test; extern crate clap; use clap::{App, Arg, ErrorKind}; +static PV_ERROR: &'static str = "error: 'slo' isn't a valid value for '--Option ' +\t[values:fast slow] + +\tDid you mean 'slow' ? + +USAGE: + clap-test --Option + +For more information try --help"; + #[test] fn possible_values_of_positional() { let m = App::new("possible_values") @@ -133,3 +144,8 @@ fn possible_values_of_option_multiple_fail() { assert!(m.is_err()); assert_eq!(m.unwrap_err().kind, ErrorKind::InvalidValue); } + +#[test] +fn possible_values_output() { + clap_test::check_err_output(clap_test::complex_app(), "clap-test -O slo", PV_ERROR, true); +} diff --git a/tests/require.rs b/tests/require.rs index b01d64e0..5ebd1b14 100644 --- a/tests/require.rs +++ b/tests/require.rs @@ -1,4 +1,5 @@ extern crate clap; +extern crate clap_test; use clap::{App, Arg, ErrorKind, ArgGroup}; @@ -295,3 +296,16 @@ fn required_unless_one_err() { assert!(res.is_err()); assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument); } + +#[test] +fn missing_required_output() { + clap_test::check_err_output(clap_test::complex_app(), "clap-test -F", +"error: The following required arguments were not provided: + + --long-option-2 + +USAGE: + clap-test -F --long-option-2 + +For more information try --help", true) +} diff --git a/tests/subcommands.rs b/tests/subcommands.rs index 2423a9d0..a9641f6f 100644 --- a/tests/subcommands.rs +++ b/tests/subcommands.rs @@ -1,3 +1,4 @@ +extern crate clap_test; extern crate clap; use clap::{App, Arg, SubCommand}; @@ -59,3 +60,16 @@ fn subcommand_multiple() { assert_eq!(sub_m.value_of("test").unwrap(), "testing"); } +#[test] +fn subcmd_did_you_mean_output() { + clap_test::check_err_output(clap_test::complex_app(), "clap-test subcm", +"error: The subcommand 'subcm' wasn't recognized +\tDid you mean 'subcmd' ? + +If you believe you received this message in error, try re-running with 'clap-test -- subcm' + +USAGE: + clap-test [FLAGS] [OPTIONS] [ARGS] [SUBCOMMAND] + +For more information try --help", true); +} diff --git a/tests/tests.rs b/tests/tests.rs index fe01d891..fd355321 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -1,8 +1,90 @@ +extern crate clap_test; #[macro_use] extern crate clap; use clap::{App, Arg}; +static SCF2OP: &'static str = "flag NOT present +option NOT present +positional NOT present +flag2 NOT present +option2 maybe present with value of: Nothing +positional2 maybe present with value of: Nothing +option3 NOT present +positional3 NOT present +option NOT present +positional NOT present +subcmd present +flag present 2 times +scoption present with value: some +An scoption: some +scpositional present with value: value +"; + +static SCFOP: &'static str = "flag NOT present +option NOT present +positional NOT present +flag2 NOT present +option2 maybe present with value of: Nothing +positional2 maybe present with value of: Nothing +option3 NOT present +positional3 NOT present +option NOT present +positional NOT present +subcmd present +flag present 1 times +scoption present with value: some +An scoption: some +scpositional present with value: value +"; + +static O2P: &'static str = "flag NOT present +option present 2 times with value: some +An option: some +An option: other +positional present with value: value +flag2 NOT present +option2 maybe present with value of: Nothing +positional2 maybe present with value of: Nothing +option3 NOT present +positional3 NOT present +option present 2 times with value: some +An option: some +An option: other +positional present with value: value +subcmd NOT present +"; + +static F2OP: &'static str = "flag present 2 times +option present 1 times with value: some +An option: some +positional present with value: value +flag2 NOT present +option2 maybe present with value of: Nothing +positional2 maybe present with value of: Nothing +option3 NOT present +positional3 NOT present +option present 1 times with value: some +An option: some +positional present with value: value +subcmd NOT present +"; + +static FOP: &'static str = "flag present 1 times +option present 1 times with value: some +An option: some +positional present with value: value +flag2 NOT present +option2 maybe present with value of: Nothing +positional2 maybe present with value of: Nothing +option3 NOT present +positional3 NOT present +option present 1 times with value: some +An option: some +positional present with value: value +subcmd NOT present +"; + arg_enum!{ #[derive(Debug)] enum Val1 { @@ -92,3 +174,156 @@ fn add_multiple_arg() { Arg::with_name("test2").short("l")]) .get_matches(); } +#[test] +fn flag_x2_opt() { + clap_test::check_complex_output("clap-test value -f -f -o some", +"flag present 2 times +option present 1 times with value: some +An option: some +positional present with value: value +flag2 NOT present +option2 maybe present with value of: Nothing +positional2 maybe present with value of: Nothing +option3 NOT present +positional3 NOT present +option present 1 times with value: some +An option: some +positional present with value: value +subcmd NOT present +"); +} + +#[test] +fn long_opt_x2_pos() { + clap_test::check_complex_output("clap-test value --option some --option other", O2P); +} + +#[test] +fn long_opt_eq_x2_pos() { + clap_test::check_complex_output("clap-test value --option=some --option=other", O2P); +} + +#[test] +fn short_opt_x2_pos() { + clap_test::check_complex_output("clap-test value -o some -o other", O2P); +} + +#[test] +fn short_opt_eq_x2_pos() { + clap_test::check_complex_output("clap-test value -o=some -o=other", O2P); +} + +#[test] +fn short_flag_x2_comb_short_opt_pos() { + clap_test::check_complex_output("clap-test value -ff -o some", F2OP); +} + +#[test] +fn short_flag_short_opt_pos() { + clap_test::check_complex_output("clap-test value -f -o some", FOP); +} + +#[test] +fn long_flag_long_opt_pos() { + clap_test::check_complex_output("clap-test value --flag --option some", FOP); +} + +#[test] +fn long_flag_long_opt_eq_pos() { + clap_test::check_complex_output("clap-test value --flag --option=some", FOP); +} + +#[test] +fn sc_long_flag_long_opt() { + clap_test::check_complex_output("clap-test subcmd value --flag --option some", SCFOP); +} + +#[test] +fn sc_long_flag_short_opt_pos() { + clap_test::check_complex_output("clap-test subcmd value --flag -o some", SCFOP); +} + +#[test] +fn sc_long_flag_long_opt_eq_pos() { + clap_test::check_complex_output("clap-test subcmd value --flag --option=some", SCFOP); +} + +#[test] +fn sc_short_flag_long_opt_pos() { + clap_test::check_complex_output("clap-test subcmd value -f --option some", SCFOP); +} + +#[test] +fn sc_short_flag_short_opt_pos() { + clap_test::check_complex_output("clap-test subcmd value -f -o some", SCFOP); +} + +#[test] +fn sc_short_flag_short_opt_eq_pos() { + clap_test::check_complex_output("clap-test subcmd value -f -o=some", SCFOP); +} + +#[test] +fn sc_short_flag_long_opt_eq_pos() { + clap_test::check_complex_output("clap-test subcmd value -f --option=some", SCFOP); +} + +#[test] +fn sc_short_flag_x2_comb_long_opt_pos() { + clap_test::check_complex_output("clap-test subcmd value -ff --option some", SCF2OP); +} + +#[test] +fn sc_short_flag_x2_comb_short_opt_pos() { + clap_test::check_complex_output("clap-test subcmd value -ff -o some", SCF2OP); +} + +#[test] +fn sc_short_flag_x2_comb_long_opt_eq_pos() { + clap_test::check_complex_output("clap-test subcmd value -ff --option=some", SCF2OP); +} + +#[test] +fn sc_short_flag_x2_comb_short_opt_eq_pos() { + clap_test::check_complex_output("clap-test subcmd value -ff -o=some", SCF2OP); +} + +#[test] +fn sc_long_flag_x2_long_opt_pos() { + clap_test::check_complex_output("clap-test subcmd value --flag --flag --option some", SCF2OP); +} + +#[test] +fn sc_long_flag_x2_short_opt_pos() { + clap_test::check_complex_output("clap-test subcmd value --flag --flag -o some", SCF2OP); +} + +#[test] +fn sc_long_flag_x2_short_opt_eq_pos() { + clap_test::check_complex_output("clap-test subcmd value --flag --flag -o=some", SCF2OP); +} + +#[test] +fn sc_long_flag_x2_long_opt_eq_pos() { + clap_test::check_complex_output("clap-test subcmd value --flag --flag --option=some", SCF2OP); +} + +#[test] +fn sc_short_flag_x2_long_opt_pos() { + clap_test::check_complex_output("clap-test subcmd value -f -f --option some", SCF2OP); +} + +#[test] +fn sc_short_flag_x2_short_opt_pos() { + clap_test::check_complex_output("clap-test subcmd value -f -f -o some", SCF2OP); +} + +#[test] +fn sc_short_flag_x2_short_opt_eq_pos() { + clap_test::check_complex_output("clap-test subcmd value -f -f -o=some", SCF2OP); +} + +#[test] +fn sc_short_flag_x2_long_opt_eq_pos() { + clap_test::check_complex_output("clap-test subcmd value -f -f --option=some", SCF2OP); +}