From bad5d19edb45c028c1f096afa3e8e335205cd043 Mon Sep 17 00:00:00 2001 From: Benjamin Fry Date: Tue, 3 Oct 2017 16:23:03 -0700 Subject: [PATCH] add env key for help msg --- src/app/help.rs | 301 +++++++++++++++++------------ src/app/mod.rs | 2 +- src/app/parser.rs | 8 +- src/app/validator.rs | 2 +- src/args/any_arg.rs | 2 +- src/args/arg.rs | 6 +- src/args/arg_builder/flag.rs | 2 +- src/args/arg_builder/option.rs | 4 +- src/args/arg_builder/positional.rs | 7 +- src/args/arg_builder/valued.rs | 4 +- tests/default_vals.rs | 13 -- tests/env.rs | 22 +++ 12 files changed, 221 insertions(+), 152 deletions(-) create mode 100644 tests/env.rs diff --git a/src/app/help.rs b/src/app/help.rs index 8baac496..6b76252b 100644 --- a/src/app/help.rs +++ b/src/app/help.rs @@ -10,7 +10,7 @@ use app::{App, AppSettings}; use app::parser::Parser; use args::{AnyArg, ArgSettings, DispOrder}; use errors::{Error, Result as ClapResult}; -use fmt::{Format, Colorizer, ColorizerOption}; +use fmt::{Colorizer, ColorizerOption, Format}; use app::usage; use map::VecMap; @@ -31,13 +31,18 @@ const TAB: &'static str = " "; // These are just convenient traits to make the code easier to read. trait ArgWithDisplay<'b, 'c>: AnyArg<'b, 'c> + Display {} -impl<'b, 'c, T> ArgWithDisplay<'b, 'c> for T where T: AnyArg<'b, 'c> + Display {} +impl<'b, 'c, T> ArgWithDisplay<'b, 'c> for T +where + T: AnyArg<'b, 'c> + Display, +{ +} trait ArgWithOrder<'b, 'c>: ArgWithDisplay<'b, 'c> + DispOrder { fn as_base(&self) -> &ArgWithDisplay<'b, 'c>; } impl<'b, 'c, T> ArgWithOrder<'b, 'c> for T - where T: ArgWithDisplay<'b, 'c> + DispOrder +where + T: ArgWithDisplay<'b, 'c> + DispOrder, { fn as_base(&self) -> &ArgWithDisplay<'b, 'c> { self } } @@ -84,29 +89,34 @@ pub struct Help<'a> { impl<'a> Help<'a> { /// Create a new `Help` instance. #[cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))] - pub fn new(w: &'a mut Write, - next_line_help: bool, - hide_pv: bool, - color: bool, - cizer: Colorizer, - term_w: Option, - max_w: Option, - use_long: bool) - -> Self { + pub fn new( + w: &'a mut Write, + next_line_help: bool, + hide_pv: bool, + color: bool, + cizer: Colorizer, + term_w: Option, + max_w: Option, + use_long: bool, + ) -> Self { debugln!("Help::new;"); Help { writer: w, next_line_help: next_line_help, hide_pv: hide_pv, term_w: match term_w { - Some(width) => if width == 0 { usize::MAX } else { width }, - None => { - cmp::min(term_size::dimensions().map_or(120, |(w, _)| w), - match max_w { - None | Some(0) => usize::MAX, - Some(mw) => mw, - }) - } + Some(width) => if width == 0 { + usize::MAX + } else { + width + }, + None => cmp::min( + term_size::dimensions().map_or(120, |(w, _)| w), + match max_w { + None | Some(0) => usize::MAX, + Some(mw) => mw, + }, + ), }, color: color, cizer: cizer, @@ -139,7 +149,12 @@ impl<'a> Help<'a> { } #[doc(hidden)] - pub fn _write_parser_help(w: &'a mut Write, parser: &Parser, stderr: bool, use_long: bool) -> ClapResult<()> { + pub fn _write_parser_help( + w: &'a mut Write, + parser: &Parser, + stderr: bool, + use_long: bool, + ) -> ClapResult<()> { debugln!("Help::write_parser_help;"); let nlh = parser.is_set(AppSettings::NextLineHelp); let hide_v = parser.is_set(AppSettings::HidePossibleValuesInHelp); @@ -148,15 +163,16 @@ impl<'a> Help<'a> { use_stderr: stderr, when: parser.color(), }); - Self::new(w, - nlh, - hide_v, - color, - cizer, - parser.meta.term_w, - parser.meta.max_w, - use_long) - .write_help(parser) + Self::new( + w, + nlh, + hide_v, + color, + cizer, + parser.meta.term_w, + parser.meta.max_w, + use_long, + ).write_help(parser) } /// Writes the parser help to the wrapped stream. @@ -177,16 +193,16 @@ impl<'a> Help<'a> { impl<'a> Help<'a> { /// Writes help for each argument in the order they were declared to the wrapped stream. fn write_args_unsorted<'b: 'd, 'c: 'd, 'd, I: 'd>(&mut self, args: I) -> io::Result<()> - where I: Iterator> + where + I: Iterator>, { debugln!("Help::write_args_unsorted;"); // The shortest an arg can legally be is 2 (i.e. '-x') self.longest = 2; let mut arg_v = Vec::with_capacity(10); for arg in args.filter(|arg| { - !(arg.is_set(ArgSettings::Hidden)) || - arg.is_set(ArgSettings::NextLineHelp) - }) { + !(arg.is_set(ArgSettings::Hidden)) || arg.is_set(ArgSettings::NextLineHelp) + }) { if arg.longest_filter() { self.longest = cmp::max(self.longest, str_width(arg.to_string().as_str())); } @@ -206,7 +222,8 @@ impl<'a> Help<'a> { /// Sorts arguments by length and display order and write their help to the wrapped stream. fn write_args<'b: 'd, 'c: 'd, 'd, I: 'd>(&mut self, args: I) -> io::Result<()> - where I: Iterator> + where + I: Iterator>, { debugln!("Help::write_args;"); // The shortest an arg can legally be is 2 (i.e. '-x') @@ -336,8 +353,8 @@ impl<'a> Help<'a> { let nlh = self.next_line_help || arg.is_set(ArgSettings::NextLineHelp); let taken = self.longest + 12; self.force_next_line = !nlh && self.term_w >= taken && - (taken as f32 / self.term_w as f32) > 0.40 && - h_w > (self.term_w - taken); + (taken as f32 / self.term_w as f32) > 0.40 && + h_w > (self.term_w - taken); debug!("Help::val: Has switch..."); if arg.has_switch() { @@ -345,10 +362,12 @@ impl<'a> Help<'a> { debugln!("Help::val: force_next_line...{:?}", self.force_next_line); debugln!("Help::val: nlh...{:?}", nlh); debugln!("Help::val: taken...{}", taken); - debugln!("Help::val: help_width > (width - taken)...{} > ({} - {})", - h_w, - self.term_w, - taken); + debugln!( + "Help::val: help_width > (width - taken)...{} > ({} - {})", + h_w, + self.term_w, + taken + ); debugln!("Help::val: longest...{}", self.longest); debug!("Help::val: next_line..."); if !(nlh || self.force_next_line) { @@ -372,7 +391,10 @@ impl<'a> Help<'a> { } } else if !(nlh || self.force_next_line) { sdebugln!("No, and not next_line"); - write_nspaces!(self.writer, self.longest + 4 - (str_width(arg.to_string().as_str()))); + write_nspaces!( + self.writer, + self.longest + 4 - (str_width(arg.to_string().as_str())) + ); } else { sdebugln!("No"); } @@ -383,19 +405,25 @@ impl<'a> Help<'a> { debugln!("Help::write_before_after_help;"); let mut help = String::from(h); // determine if our help fits or needs to wrap - debugln!("Help::write_before_after_help: Term width...{}", - self.term_w); + debugln!( + "Help::write_before_after_help: Term width...{}", + self.term_w + ); let too_long = str_width(h) >= self.term_w; debug!("Help::write_before_after_help: Too long..."); if too_long || h.contains("{n}") { sdebugln!("Yes"); debugln!("Help::write_before_after_help: help: {}", help); - debugln!("Help::write_before_after_help: help width: {}", - str_width(&*help)); + debugln!( + "Help::write_before_after_help: help width: {}", + str_width(&*help) + ); // Determine how many newlines we need to insert - debugln!("Help::write_before_after_help: Usable space: {}", - self.term_w); + debugln!( + "Help::write_before_after_help: Usable space: {}", + self.term_w + ); help = wrap_help(&help.replace("{n}", "\n"), self.term_w); } else { sdebugln!("No"); @@ -467,40 +495,57 @@ impl<'a> Help<'a> { if !a.is_set(ArgSettings::HideDefaultValue) { if let Some(pv) = a.default_val() { debugln!("Help::spec_vals: Found default value...[{:?}]", pv); - spec_vals.push(format!(" [default: {}]", - if self.color { - self.cizer.good(pv.to_string_lossy()) - } else { - Format::None(pv.to_string_lossy()) - })); + spec_vals.push(format!( + " [default: {}]", + if self.color { + self.cizer.good(pv.to_string_lossy()) + } else { + Format::None(pv.to_string_lossy()) + } + )); } - // FIXME: add [env::{}: {}] here + } + if let Some(ref env) = a.env() { + debugln!( + "Help::spec_vals: Found environment variable...[{:?}:{:?}]", + env.0, + env.1 + ); + spec_vals.push(format!( + " [env:{}:{}]", + env.0.to_string_lossy(), + env.1.to_string_lossy() + )); } if let Some(ref aliases) = a.aliases() { debugln!("Help::spec_vals: Found aliases...{:?}", aliases); - spec_vals.push(format!(" [aliases: {}]", - if self.color { - aliases - .iter() - .map(|v| format!("{}", self.cizer.good(v))) - .collect::>() - .join(", ") - } else { - aliases.join(", ") - })); + spec_vals.push(format!( + " [aliases: {}]", + if self.color { + aliases + .iter() + .map(|v| format!("{}", self.cizer.good(v))) + .collect::>() + .join(", ") + } else { + aliases.join(", ") + } + )); } if !self.hide_pv && !a.is_set(ArgSettings::HidePossibleValues) { if let Some(pv) = a.possible_vals() { debugln!("Help::spec_vals: Found possible vals...{:?}", pv); spec_vals.push(if self.color { - format!(" [values: {}]", - pv.iter() - .map(|v| format!("{}", self.cizer.good(v))) - .collect::>() - .join(", ")) - } else { - format!(" [values: {}]", pv.join(", ")) - }); + format!( + " [values: {}]", + pv.iter() + .map(|v| format!("{}", self.cizer.good(v))) + .collect::>() + .join(", ") + ) + } else { + format!(" [values: {}]", pv.join(", ")) + }); } } spec_vals.join(" ") @@ -579,12 +624,11 @@ impl<'a> Help<'a> { self.longest = 2; let mut ord_m = VecMap::new(); for sc in parser - .subcommands - .iter() - .filter(|s| !s.p.is_set(AppSettings::Hidden)) { - let btm = ord_m - .entry(sc.p.meta.disp_ord) - .or_insert(BTreeMap::new()); + .subcommands + .iter() + .filter(|s| !s.p.is_set(AppSettings::Hidden)) + { + let btm = ord_m.entry(sc.p.meta.disp_ord).or_insert(BTreeMap::new()); self.longest = cmp::max(self.longest, str_width(sc.p.meta.name.as_str())); //self.longest = cmp::max(self.longest, sc.p.meta.name.len()); btm.insert(sc.p.meta.name.clone(), sc.clone()); @@ -677,10 +721,12 @@ impl<'a> Help<'a> { } color!(self, "\nUSAGE:", warning)?; - write!(self.writer, - "\n{}{}\n\n", - TAB, - usage::create_usage_no_title(parser, &[]))?; + write!( + self.writer, + "\n{}{}\n\n", + TAB, + usage::create_usage_no_title(parser, &[]) + )?; let flags = parser.has_flags(); let pos = parser.has_positionals(); @@ -746,21 +792,20 @@ fn copy_until(r: &mut R, w: &mut W, delimiter_byte: u8) -> Co /// - `None`: The reader was consumed. /// - `Some(Ok(0))`: No tag was captured but the reader still contains data. /// - `Some(Ok(length>0))`: a tag with `length` was captured to the `tag_buffer`. -fn copy_and_capture(r: &mut R, - w: &mut W, - tag_buffer: &mut Cursor>) - -> Option> { +fn copy_and_capture( + r: &mut R, + w: &mut W, + tag_buffer: &mut Cursor>, +) -> Option> { use self::CopyUntilResult::*; debugln!("copy_and_capture;"); // Find the opening byte. match copy_until(r, w, b'{') { - // The end of the reader was reached without finding the opening tag. // (either with or without having copied data to the writer) // Return None indicating that we are done. - ReaderEmpty | - DelimiterNotFound(_) => None, + ReaderEmpty | DelimiterNotFound(_) => None, // Something went wrong. ReadError(e) | WriteError(e) => Some(Err(e)), @@ -768,7 +813,6 @@ fn copy_and_capture(r: &mut R, // The opening byte was found. // (either with or without having copied data to the writer) DelimiterFound(_) => { - // Lets reset the buffer first and find out how long it is. tag_buffer.set_position(0); let buffer_size = tag_buffer.get_ref().len(); @@ -776,7 +820,6 @@ fn copy_and_capture(r: &mut R, // Find the closing byte,limiting the reader to the length of the buffer. let mut rb = r.take(buffer_size as u64); match copy_until(&mut rb, tag_buffer, b'}') { - // We were already at the end of the reader. // Return None indicating that we are done. ReaderEmpty => None, @@ -788,17 +831,13 @@ fn copy_and_capture(r: &mut R, // The end of the reader was found without finding the closing tag. // Write the opening byte and captured text to the writer. // Return 0 indicating that nothing was caputred but the reader still contains data. - DelimiterNotFound(not_tag_length) => { - match w.write(b"{") { + DelimiterNotFound(not_tag_length) => match w.write(b"{") { + Err(e) => Some(Err(e)), + _ => match w.write(&tag_buffer.get_ref()[0..not_tag_length]) { Err(e) => Some(Err(e)), - _ => { - match w.write(&tag_buffer.get_ref()[0..not_tag_length]) { - Err(e) => Some(Err(e)), - _ => Some(Ok(0)), - } - } - } - } + _ => Some(Ok(0)), + }, + }, ReadError(e) | WriteError(e) => Some(Err(e)), } @@ -849,10 +888,12 @@ impl<'a> Help<'a> { }; debugln!("Help::write_template_help:iter: tag_buf={};", unsafe { - String::from_utf8_unchecked(tag_buf.get_ref()[0..tag_length] - .iter() - .map(|&i| i) - .collect::>()) + String::from_utf8_unchecked( + tag_buf.get_ref()[0..tag_length] + .iter() + .map(|&i| i) + .collect::>(), + ) }); match &tag_buf.get_ref()[0..tag_length] { b"?" => { @@ -862,24 +903,32 @@ impl<'a> Help<'a> { self.write_bin_name(parser)?; } b"version" => { - write!(self.writer, - "{}", - parser.meta.version.unwrap_or("unknown version"))?; + write!( + self.writer, + "{}", + parser.meta.version.unwrap_or("unknown version") + )?; } b"author" => { - write!(self.writer, - "{}", - parser.meta.author.unwrap_or("unknown author"))?; + write!( + self.writer, + "{}", + parser.meta.author.unwrap_or("unknown author") + )?; } b"about" => { - write!(self.writer, - "{}", - parser.meta.about.unwrap_or("unknown about"))?; + write!( + self.writer, + "{}", + parser.meta.about.unwrap_or("unknown about") + )?; } b"long-about" => { - write!(self.writer, - "{}", - parser.meta.long_about.unwrap_or("unknown about"))?; + write!( + self.writer, + "{}", + parser.meta.long_about.unwrap_or("unknown about") + )?; } b"usage" => { write!(self.writer, "{}", usage::create_usage_no_title(parser, &[]))?; @@ -907,14 +956,18 @@ impl<'a> Help<'a> { self.write_subcommands(parser)?; } b"after-help" => { - write!(self.writer, - "{}", - parser.meta.more_help.unwrap_or("unknown after-help"))?; + write!( + self.writer, + "{}", + parser.meta.more_help.unwrap_or("unknown after-help") + )?; } b"before-help" => { - write!(self.writer, - "{}", - parser.meta.pre_help.unwrap_or("unknown before-help"))?; + write!( + self.writer, + "{}", + parser.meta.pre_help.unwrap_or("unknown before-help") + )?; } // Unknown tag, write it back. r => { diff --git a/src/app/mod.rs b/src/app/mod.rs index fdf07e65..98da8b9c 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -1796,7 +1796,7 @@ impl<'n, 'e> AnyArg<'n, 'e> for App<'n, 'e> { fn default_vals_ifs(&self) -> Option, &'e OsStr)>> { None } - fn from_env(&self) -> Option<&OsString> { None } + fn env<'s>(&'s self) -> Option<(&'n OsStr, &'s OsString)> { None } fn longest_filter(&self) -> bool { true } fn aliases(&self) -> Option> { if let Some(ref aliases) = self.p.meta.aliases { diff --git a/src/app/parser.rs b/src/app/parser.rs index b0e135cd..afcfbc08 100644 --- a/src/app/parser.rs +++ b/src/app/parser.rs @@ -1789,19 +1789,19 @@ impl<'a, 'b> Parser<'a, 'b> Ok(()) } - pub fn add_from_env(&mut self, matcher: &mut ArgMatcher<'a>) -> ClapResult<()> { + pub fn add_env(&mut self, matcher: &mut ArgMatcher<'a>) -> ClapResult<()> { macro_rules! add_val { ($_self:ident, $a:ident, $m:ident) => { - if let Some(ref val) = $a.v.from_env { + if let Some(ref val) = $a.v.env { if $m.get($a.b.name).map(|ma| ma.vals.len()).map(|len| len == 0).unwrap_or(false) { - $_self.add_val_to_arg($a, OsStr::new(val), $m)?; + $_self.add_val_to_arg($a, OsStr::new(&val.1), $m)?; if $_self.cache.map_or(true, |name| name != $a.name()) { arg_post_processing!($_self, $a, $m); $_self.cache = Some($a.name()); } } else { - $_self.add_val_to_arg($a, OsStr::new(val), $m)?; + $_self.add_val_to_arg($a, OsStr::new(&val.1), $m)?; if $_self.cache.map_or(true, |name| name != $a.name()) { arg_post_processing!($_self, $a, $m); diff --git a/src/app/validator.rs b/src/app/validator.rs index 3077af0b..c65ecd8d 100644 --- a/src/app/validator.rs +++ b/src/app/validator.rs @@ -28,7 +28,7 @@ impl<'a, 'b, 'z> Validator<'a, 'b, 'z> { -> ClapResult<()> { debugln!("Validator::validate;"); let mut reqs_validated = false; - self.0.add_from_env(matcher)?; + self.0.add_env(matcher)?; self.0.add_defaults(matcher)?; if let ParseResult::Opt(a) = needs_val_of { debugln!("Validator::validate: needs_val_of={:?}", a); diff --git a/src/args/any_arg.rs b/src/args/any_arg.rs index 1767a0ac..c574f5c3 100644 --- a/src/args/any_arg.rs +++ b/src/args/any_arg.rs @@ -33,7 +33,7 @@ pub trait AnyArg<'n, 'e>: std_fmt::Display { fn long_help(&self) -> Option<&'e str>; fn default_val(&self) -> Option<&'e OsStr>; fn default_vals_ifs(&self) -> Option, &'e OsStr)>>; - fn from_env(&self) -> Option<&OsString>; + fn env<'s>(&'s self) -> Option<(&'n OsStr, &'s OsString)>; fn longest_filter(&self) -> bool; fn val_terminator(&self) -> Option<&'e str>; } diff --git a/src/args/arg.rs b/src/args/arg.rs index bbfcf505..8c8bd617 100644 --- a/src/args/arg.rs +++ b/src/args/arg.rs @@ -128,7 +128,7 @@ impl<'a, 'b> Arg<'a, 'b> { "default_value" => yaml_to_str!(a, v, default_value), "default_value_if" => yaml_tuple3!(a, v, default_value_if), "default_value_ifs" => yaml_tuple3!(a, v, default_value_if), - "from_env" => yaml_to_str!(a, v, from_env), + "env" => yaml_to_str!(a, v, env), "value_names" => yaml_vec_or_str!(v, a, value_name), "groups" => yaml_vec_or_str!(v, a, group), "requires" => yaml_vec_or_str!(v, a, requires), @@ -3315,10 +3315,10 @@ impl<'a, 'b> Arg<'a, 'b> { /// Specifies that if the value is not passed in as an argument, that it should be retrieved /// from the environment if available. If it is not present in the environment, then default /// rules will apply. - pub fn from_env>(mut self, name: K) -> Self { + pub fn env(mut self, name: &'a OsStr) -> Self { self.setb(ArgSettings::TakesValue); - self.v.from_env = env::var_os(name); + self.v.env = env::var_os(name).map(|value| (name, value)); self } diff --git a/src/args/arg_builder/flag.rs b/src/args/arg_builder/flag.rs index 89b53c7d..36977f8e 100644 --- a/src/args/arg_builder/flag.rs +++ b/src/args/arg_builder/flag.rs @@ -89,7 +89,7 @@ impl<'n, 'e> AnyArg<'n, 'e> for FlagBuilder<'n, 'e> { fn default_vals_ifs(&self) -> Option, &'e OsStr)>> { None } - fn from_env(&self) -> Option<&OsString> { None } + fn env<'s>(&'s self) -> Option<(&'n OsStr, &'s OsString)> { None } fn longest_filter(&self) -> bool { self.s.long.is_some() } fn aliases(&self) -> Option> { if let Some(ref aliases) = self.s.aliases { diff --git a/src/args/arg_builder/option.rs b/src/args/arg_builder/option.rs index 644e43f9..08248973 100644 --- a/src/args/arg_builder/option.rs +++ b/src/args/arg_builder/option.rs @@ -140,7 +140,9 @@ impl<'n, 'e> AnyArg<'n, 'e> for OptBuilder<'n, 'e> { fn default_vals_ifs(&self) -> Option, &'e OsStr)>> { self.v.default_vals_ifs.as_ref().map(|vm| vm.values()) } - fn from_env(&self) -> Option<&OsString> { self.v.from_env.as_ref() } + fn env<'s>(&'s self) -> Option<(&'n OsStr, &'s OsString)> { + self.v.env.as_ref().map(|&(key, ref value)| (key, value)) + } fn longest_filter(&self) -> bool { true } fn aliases(&self) -> Option> { if let Some(ref aliases) = self.s.aliases { diff --git a/src/args/arg_builder/positional.rs b/src/args/arg_builder/positional.rs index a6b54bca..b107e1ef 100644 --- a/src/args/arg_builder/positional.rs +++ b/src/args/arg_builder/positional.rs @@ -152,7 +152,12 @@ impl<'n, 'e> AnyArg<'n, 'e> for PosBuilder<'n, 'e> { self.v.default_vals_ifs.as_ref().map(|vm| vm.values()) } fn default_val(&self) -> Option<&'e OsStr> { self.v.default_val } - fn from_env(&self) -> Option<&OsString> { self.v.from_env.as_ref() } + fn env<'s>(&'s self) -> Option<(&'n OsStr, &'s OsString)> { + self.v + .env + .as_ref() + .map(|&(key, ref value)| (key, value)) + } fn longest_filter(&self) -> bool { true } fn aliases(&self) -> Option> { None } } diff --git a/src/args/arg_builder/valued.rs b/src/args/arg_builder/valued.rs index e661b308..5ea0bb94 100644 --- a/src/args/arg_builder/valued.rs +++ b/src/args/arg_builder/valued.rs @@ -21,7 +21,7 @@ where pub val_delim: Option, pub default_val: Option<&'b OsStr>, pub default_vals_ifs: Option, &'b OsStr)>>, - pub from_env: Option, + pub env: Option<(&'a OsStr, OsString)>, pub terminator: Option<&'b str>, } @@ -38,7 +38,7 @@ impl<'n, 'e> Default for Valued<'n, 'e> { val_delim: None, default_val: None, default_vals_ifs: None, - from_env: None, + env: None, terminator: None, } } diff --git a/tests/default_vals.rs b/tests/default_vals.rs index 7f160f34..cee8adfc 100644 --- a/tests/default_vals.rs +++ b/tests/default_vals.rs @@ -479,16 +479,3 @@ fn conditional_reqs_pass() { assert_eq!(m.value_of("output"), Some("other")); assert_eq!(m.value_of("input"), Some("some")); } - -#[test] -fn from_env_no_default() { - std::env::set_var("CLP_TEST_ENV", "from_env"); - - let r = App::new("df") - .arg(Arg::from_usage("[arg] 'some opt'").from_env("CLP_TEST_ENV")) - .get_matches_from_safe(vec![""]); - assert!(r.is_ok()); - let m = r.unwrap(); - // assert!(m.is_present("arg")); // TODO: should this be true? - assert_eq!(m.value_of("arg").unwrap(), "from_env"); -} diff --git a/tests/env.rs b/tests/env.rs new file mode 100644 index 00000000..3673d287 --- /dev/null +++ b/tests/env.rs @@ -0,0 +1,22 @@ +extern crate clap; +extern crate regex; + +use std::env; +use std::ffi::OsStr; + +use clap::{App, Arg, ErrorKind}; + +#[test] +fn env_no_default() { + env::set_var("CLP_TEST_ENV", "env"); + + let r = App::new("df") + .arg( + Arg::from_usage("[arg] 'some opt'").env(OsStr::new("CLP_TEST_ENV")), + ) + .get_matches_from_safe(vec![""]); + assert!(r.is_ok()); + let m = r.unwrap(); + // assert!(m.is_present("arg")); // TODO: should this be true? + assert_eq!(m.value_of("arg").unwrap(), "env"); +}