feat(error): Break out error-context feature flag

This is a cheap pass at creating this to allow cutting out the cost of
rich error information / programmatic error information.

This cuts about 20 KiB off of the binary.

There is more we could cut out, like collecting of used arguments for
the usage, but I want to keep the conditionals simple.
This commit is contained in:
Ed Page 2022-09-19 09:59:04 -05:00
parent b4788d51f1
commit 2d83a7b12e
24 changed files with 568 additions and 348 deletions

View file

@ -268,6 +268,7 @@ Behavior Changes
- Allow resetting most builder methods
- Can now pass runtime generated data to `Command`, `Arg`, `ArgGroup`, `PossibleValue`, etc without managing lifetimes with the `string` feature flag (#2150, #4223)
- *(error)* `Error::apply` for changing the formatter for dropping binary size (#4111)
- *(error)* New default `error-context` feature flag that can be turned off for smaller binaries
- *(help)* Show `PossibleValue::help` in long help (`--help`) (#3312)
- *(help)* New `{tab}` variable for `Command::help_template` (#4161)

View file

@ -57,6 +57,7 @@ pre-release-replacements = [
default = [
"std",
"color",
"error-context",
"suggestions",
]
debug = ["clap_derive/debug", "dep:backtrace"] # Enables debug messages
@ -65,7 +66,8 @@ unstable-doc = ["derive", "cargo", "wrap_help", "env", "unicode", "string", "uns
# Used in default
std = [] # support for no_std in a backwards-compatible way
color = ["dep:atty", "dep:termcolor"]
suggestions = ["dep:strsim"]
error-context = []
suggestions = ["dep:strsim", "error-context"]
# Optional
deprecated = ["clap_derive?/deprecated"] # Guided experience to prepare for next breaking release (at different stages of development, this may become default)

View file

@ -6,6 +6,7 @@
//!
//! * **std**: _Not Currently Used._ Placeholder for supporting `no_std` environments in a backwards compatible manner.
//! * **color**: Turns on colored error messages.
//! * **error-context**: Include contextual information for errors (which arg failed, etc)
//! * **suggestions**: Turns on the `Did you mean '--myoption'?` feature for when users make typos.
//!
//! #### Optional features

View file

@ -29,6 +29,7 @@ impl StyledStr {
self.stylize_(Some(Style::Good), msg.into());
}
#[cfg_attr(not(feature = "error-context"), allow(dead_code))]
pub(crate) fn warning(&mut self, msg: impl Into<String>) {
self.stylize_(Some(Style::Warning), msg.into());
}

View file

@ -1,6 +1,7 @@
/// Semantics for a piece of error information
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[non_exhaustive]
#[cfg(feature = "error-context")]
pub enum ContextKind {
/// The cause of the error
InvalidSubcommand,
@ -66,6 +67,7 @@ impl std::fmt::Display for ContextKind {
/// A piece of error information
#[derive(Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
#[cfg(feature = "error-context")]
pub enum ContextValue {
/// [`ContextKind`] is self-sufficient, no additional information needed
None,

View file

@ -1,9 +1,13 @@
#![allow(missing_copy_implementations)]
#![allow(missing_debug_implementations)]
#![cfg_attr(not(feature = "error-context"), allow(dead_code))]
#![cfg_attr(not(feature = "error-context"), allow(unused_imports))]
use crate::builder::Command;
use crate::builder::StyledStr;
#[cfg(feature = "error-context")]
use crate::error::ContextKind;
#[cfg(feature = "error-context")]
use crate::error::ContextValue;
use crate::error::ErrorKind;
use crate::output::TAB;
@ -16,7 +20,10 @@ pub trait ErrorFormatter: Sized {
/// Report [`ErrorKind`]
///
/// No context is included
/// No context is included.
///
/// **NOTE:** Consider removing the [`error-context`][crate::_features] default feature if using this to remove all
/// overhead for [`RichFormatter`].
#[non_exhaustive]
pub struct KindFormatter;
@ -38,8 +45,10 @@ impl ErrorFormatter for KindFormatter {
/// Dump the error context reported
#[non_exhaustive]
#[cfg(feature = "error-context")]
pub struct RawFormatter;
#[cfg(feature = "error-context")]
impl ErrorFormatter for RawFormatter {
fn format_error(error: &crate::Error<Self>) -> StyledStr {
let mut styled = StyledStr::new();
@ -73,8 +82,10 @@ impl ErrorFormatter for RawFormatter {
/// Richly formatted error context
#[non_exhaustive]
#[cfg(feature = "error-context")]
pub struct RichFormatter;
#[cfg(feature = "error-context")]
impl ErrorFormatter for RichFormatter {
fn format_error(error: &crate::Error<Self>) -> StyledStr {
let mut styled = StyledStr::new();
@ -107,6 +118,7 @@ fn start_error(styled: &mut StyledStr) {
}
#[must_use]
#[cfg(feature = "error-context")]
fn write_dynamic_context(error: &crate::Error, styled: &mut StyledStr) -> bool {
match error.kind() {
ErrorKind::ArgumentConflict => {

View file

@ -1,5 +1,11 @@
//! Error reporting
#![cfg_attr(not(feature = "error-context"), allow(dead_code))]
#![cfg_attr(not(feature = "error-context"), allow(unused_imports))]
#![cfg_attr(not(feature = "error-context"), allow(unused_variables))]
#![cfg_attr(not(feature = "error-context"), allow(unused_mut))]
#![cfg_attr(not(feature = "error-context"), allow(clippy::let_and_return))]
// Std
use std::{
borrow::Cow,
@ -19,18 +25,27 @@ use crate::util::FlatMap;
use crate::util::{color::ColorChoice, safe_exit, SUCCESS_CODE, USAGE_CODE};
use crate::Command;
#[cfg(feature = "error-context")]
mod context;
mod format;
mod kind;
pub use context::ContextKind;
pub use context::ContextValue;
pub use format::ErrorFormatter;
pub use format::KindFormatter;
pub use format::RawFormatter;
pub use format::RichFormatter;
pub use kind::ErrorKind;
#[cfg(feature = "error-context")]
pub use context::ContextKind;
#[cfg(feature = "error-context")]
pub use context::ContextValue;
#[cfg(feature = "error-context")]
pub use format::RawFormatter;
#[cfg(feature = "error-context")]
pub use format::RichFormatter;
#[cfg(not(feature = "error-context"))]
pub use KindFormatter as DefaultFormatter;
#[cfg(feature = "error-context")]
pub use RichFormatter as DefaultFormatter;
/// Short hand for [`Result`] type
@ -51,6 +66,7 @@ pub struct Error<F: ErrorFormatter = DefaultFormatter> {
#[derive(Debug)]
struct ErrorInner {
kind: ErrorKind,
#[cfg(feature = "error-context")]
context: FlatMap<ContextKind, ContextValue>,
message: Option<Message>,
source: Option<Box<dyn error::Error + Send + Sync>>,
@ -112,12 +128,14 @@ impl<F: ErrorFormatter> Error<F> {
}
/// Additional information to further qualify the error
#[cfg(feature = "error-context")]
pub fn context(&self) -> impl Iterator<Item = (ContextKind, &ContextValue)> {
self.inner.context.iter().map(|(k, v)| (*k, v))
}
/// Lookup a piece of context
#[inline(never)]
#[cfg(feature = "error-context")]
pub fn get(&self, kind: ContextKind) -> Option<&ContextValue> {
self.inner.context.get(&kind)
}
@ -183,6 +201,7 @@ impl<F: ErrorFormatter> Error<F> {
Self {
inner: Box::new(ErrorInner {
kind,
#[cfg(feature = "error-context")]
context: FlatMap::new(),
message: None,
source: None,
@ -233,6 +252,7 @@ impl<F: ErrorFormatter> Error<F> {
/// Does not verify if `ContextKind` is already present
#[inline(never)]
#[cfg(feature = "error-context")]
pub(crate) fn insert_context_unchecked(
mut self,
kind: ContextKind,
@ -244,6 +264,7 @@ impl<F: ErrorFormatter> Error<F> {
/// Does not verify if `ContextKind` is already present
#[inline(never)]
#[cfg(feature = "error-context")]
pub(crate) fn extend_context_unchecked<const N: usize>(
mut self,
context: [(ContextKind, ContextValue); N],
@ -274,18 +295,23 @@ impl<F: ErrorFormatter> Error<F> {
mut others: Vec<String>,
usage: StyledStr,
) -> Self {
let others = match others.len() {
0 => ContextValue::None,
1 => ContextValue::String(others.pop().unwrap()),
_ => ContextValue::Strings(others),
};
Self::new(ErrorKind::ArgumentConflict)
.with_cmd(cmd)
.extend_context_unchecked([
let mut err = Self::new(ErrorKind::ArgumentConflict).with_cmd(cmd);
#[cfg(feature = "error-context")]
{
let others = match others.len() {
0 => ContextValue::None,
1 => ContextValue::String(others.pop().unwrap()),
_ => ContextValue::Strings(others),
};
err = err.extend_context_unchecked([
(ContextKind::InvalidArg, ContextValue::String(arg)),
(ContextKind::PriorArg, others),
(ContextKind::Usage, ContextValue::StyledStr(usage)),
])
]);
}
err
}
pub(crate) fn empty_value(cmd: &Command, good_vals: &[String], arg: String) -> Self {
@ -293,12 +319,17 @@ impl<F: ErrorFormatter> Error<F> {
}
pub(crate) fn no_equals(cmd: &Command, arg: String, usage: StyledStr) -> Self {
Self::new(ErrorKind::NoEquals)
.with_cmd(cmd)
.extend_context_unchecked([
let mut err = Self::new(ErrorKind::NoEquals).with_cmd(cmd);
#[cfg(feature = "error-context")]
{
err = err.extend_context_unchecked([
(ContextKind::InvalidArg, ContextValue::String(arg)),
(ContextKind::Usage, ContextValue::StyledStr(usage)),
])
]);
}
err
}
pub(crate) fn invalid_value(
@ -308,9 +339,11 @@ impl<F: ErrorFormatter> Error<F> {
arg: String,
) -> Self {
let suggestion = suggestions::did_you_mean(&bad_val, good_vals.iter()).pop();
let mut err = Self::new(ErrorKind::InvalidValue)
.with_cmd(cmd)
.extend_context_unchecked([
let mut err = Self::new(ErrorKind::InvalidValue).with_cmd(cmd);
#[cfg(feature = "error-context")]
{
err = err.extend_context_unchecked([
(ContextKind::InvalidArg, ContextValue::String(arg)),
(ContextKind::InvalidValue, ContextValue::String(bad_val)),
(
@ -318,12 +351,14 @@ impl<F: ErrorFormatter> Error<F> {
ContextValue::Strings(good_vals.iter().map(|s| (*s).to_owned()).collect()),
),
]);
if let Some(suggestion) = suggestion {
err = err.insert_context_unchecked(
ContextKind::SuggestedValue,
ContextValue::String(suggestion),
);
if let Some(suggestion) = suggestion {
err = err.insert_context_unchecked(
ContextKind::SuggestedValue,
ContextValue::String(suggestion),
);
}
}
err
}
@ -335,9 +370,11 @@ impl<F: ErrorFormatter> Error<F> {
usage: StyledStr,
) -> Self {
let suggestion = format!("{} -- {}", name, subcmd);
Self::new(ErrorKind::InvalidSubcommand)
.with_cmd(cmd)
.extend_context_unchecked([
let mut err = Self::new(ErrorKind::InvalidSubcommand).with_cmd(cmd);
#[cfg(feature = "error-context")]
{
err = err.extend_context_unchecked([
(ContextKind::InvalidSubcommand, ContextValue::String(subcmd)),
(
ContextKind::SuggestedSubcommand,
@ -348,16 +385,24 @@ impl<F: ErrorFormatter> Error<F> {
ContextValue::String(suggestion),
),
(ContextKind::Usage, ContextValue::StyledStr(usage)),
])
]);
}
err
}
pub(crate) fn unrecognized_subcommand(cmd: &Command, subcmd: String, usage: StyledStr) -> Self {
Self::new(ErrorKind::InvalidSubcommand)
.with_cmd(cmd)
.extend_context_unchecked([
let mut err = Self::new(ErrorKind::InvalidSubcommand).with_cmd(cmd);
#[cfg(feature = "error-context")]
{
err = err.extend_context_unchecked([
(ContextKind::InvalidSubcommand, ContextValue::String(subcmd)),
(ContextKind::Usage, ContextValue::StyledStr(usage)),
])
]);
}
err
}
pub(crate) fn missing_required_argument(
@ -365,27 +410,43 @@ impl<F: ErrorFormatter> Error<F> {
required: Vec<String>,
usage: StyledStr,
) -> Self {
Self::new(ErrorKind::MissingRequiredArgument)
.with_cmd(cmd)
.extend_context_unchecked([
let mut err = Self::new(ErrorKind::MissingRequiredArgument).with_cmd(cmd);
#[cfg(feature = "error-context")]
{
err = err.extend_context_unchecked([
(ContextKind::InvalidArg, ContextValue::Strings(required)),
(ContextKind::Usage, ContextValue::StyledStr(usage)),
])
]);
}
err
}
pub(crate) fn missing_subcommand(cmd: &Command, name: String, usage: StyledStr) -> Self {
Self::new(ErrorKind::MissingSubcommand)
.with_cmd(cmd)
.extend_context_unchecked([
let mut err = Self::new(ErrorKind::MissingSubcommand).with_cmd(cmd);
#[cfg(feature = "error-context")]
{
err = err.extend_context_unchecked([
(ContextKind::InvalidSubcommand, ContextValue::String(name)),
(ContextKind::Usage, ContextValue::StyledStr(usage)),
])
]);
}
err
}
pub(crate) fn invalid_utf8(cmd: &Command, usage: StyledStr) -> Self {
Self::new(ErrorKind::InvalidUtf8)
.with_cmd(cmd)
.extend_context_unchecked([(ContextKind::Usage, ContextValue::StyledStr(usage))])
let mut err = Self::new(ErrorKind::InvalidUtf8).with_cmd(cmd);
#[cfg(feature = "error-context")]
{
err = err
.extend_context_unchecked([(ContextKind::Usage, ContextValue::StyledStr(usage))]);
}
err
}
pub(crate) fn too_many_values(
@ -394,13 +455,18 @@ impl<F: ErrorFormatter> Error<F> {
arg: String,
usage: StyledStr,
) -> Self {
Self::new(ErrorKind::TooManyValues)
.with_cmd(cmd)
.extend_context_unchecked([
let mut err = Self::new(ErrorKind::TooManyValues).with_cmd(cmd);
#[cfg(feature = "error-context")]
{
err = err.extend_context_unchecked([
(ContextKind::InvalidArg, ContextValue::String(arg)),
(ContextKind::InvalidValue, ContextValue::String(val)),
(ContextKind::Usage, ContextValue::StyledStr(usage)),
])
]);
}
err
}
pub(crate) fn too_few_values(
@ -410,9 +476,11 @@ impl<F: ErrorFormatter> Error<F> {
curr_vals: usize,
usage: StyledStr,
) -> Self {
Self::new(ErrorKind::TooFewValues)
.with_cmd(cmd)
.extend_context_unchecked([
let mut err = Self::new(ErrorKind::TooFewValues).with_cmd(cmd);
#[cfg(feature = "error-context")]
{
err = err.extend_context_unchecked([
(ContextKind::InvalidArg, ContextValue::String(arg)),
(
ContextKind::MinValues,
@ -423,7 +491,10 @@ impl<F: ErrorFormatter> Error<F> {
ContextValue::Number(curr_vals as isize),
),
(ContextKind::Usage, ContextValue::StyledStr(usage)),
])
]);
}
err
}
pub(crate) fn value_validation(
@ -431,12 +502,17 @@ impl<F: ErrorFormatter> Error<F> {
val: String,
err: Box<dyn error::Error + Send + Sync>,
) -> Self {
Self::new(ErrorKind::ValueValidation)
.set_source(err)
.extend_context_unchecked([
let mut err = Self::new(ErrorKind::ValueValidation).set_source(err);
#[cfg(feature = "error-context")]
{
err = err.extend_context_unchecked([
(ContextKind::InvalidArg, ContextValue::String(arg)),
(ContextKind::InvalidValue, ContextValue::String(val)),
])
]);
}
err
}
pub(crate) fn wrong_number_of_values(
@ -446,9 +522,11 @@ impl<F: ErrorFormatter> Error<F> {
curr_vals: usize,
usage: StyledStr,
) -> Self {
Self::new(ErrorKind::WrongNumberOfValues)
.with_cmd(cmd)
.extend_context_unchecked([
let mut err = Self::new(ErrorKind::WrongNumberOfValues).with_cmd(cmd);
#[cfg(feature = "error-context")]
{
err = err.extend_context_unchecked([
(ContextKind::InvalidArg, ContextValue::String(arg)),
(
ContextKind::ExpectedNumValues,
@ -459,7 +537,10 @@ impl<F: ErrorFormatter> Error<F> {
ContextValue::Number(curr_vals as isize),
),
(ContextKind::Usage, ContextValue::StyledStr(usage)),
])
]);
}
err
}
pub(crate) fn unknown_argument(
@ -468,35 +549,44 @@ impl<F: ErrorFormatter> Error<F> {
did_you_mean: Option<(String, Option<String>)>,
usage: StyledStr,
) -> Self {
let mut err = Self::new(ErrorKind::UnknownArgument)
.with_cmd(cmd)
.extend_context_unchecked([
let mut err = Self::new(ErrorKind::UnknownArgument).with_cmd(cmd);
#[cfg(feature = "error-context")]
{
err = err.extend_context_unchecked([
(ContextKind::InvalidArg, ContextValue::String(arg)),
(ContextKind::Usage, ContextValue::StyledStr(usage)),
]);
if let Some((flag, sub)) = did_you_mean {
err = err.insert_context_unchecked(
ContextKind::SuggestedArg,
ContextValue::String(format!("--{}", flag)),
);
if let Some(sub) = sub {
if let Some((flag, sub)) = did_you_mean {
err = err.insert_context_unchecked(
ContextKind::SuggestedSubcommand,
ContextValue::String(sub),
ContextKind::SuggestedArg,
ContextValue::String(format!("--{}", flag)),
);
if let Some(sub) = sub {
err = err.insert_context_unchecked(
ContextKind::SuggestedSubcommand,
ContextValue::String(sub),
);
}
}
}
err
}
pub(crate) fn unnecessary_double_dash(cmd: &Command, arg: String, usage: StyledStr) -> Self {
Self::new(ErrorKind::UnknownArgument)
.with_cmd(cmd)
.extend_context_unchecked([
let mut err = Self::new(ErrorKind::UnknownArgument).with_cmd(cmd);
#[cfg(feature = "error-context")]
{
err = err.extend_context_unchecked([
(ContextKind::InvalidArg, ContextValue::String(arg)),
(ContextKind::TrailingArg, ContextValue::Bool(true)),
(ContextKind::Usage, ContextValue::StyledStr(usage)),
])
]);
}
err
}
fn formatted(&self) -> Cow<'_, StyledStr> {

View file

@ -1,7 +1,8 @@
use super::utils;
use clap::{arg, error::ErrorKind, Arg, ArgAction, ArgGroup, Command};
#[cfg(feature = "error-context")]
use super::utils;
#[test]
fn flag_conflict() {
let result = Command::new("flag_conflict")
@ -271,6 +272,7 @@ fn get_arg_conflicts_with_group() {
}
#[test]
#[cfg(feature = "error-context")]
fn conflict_output() {
static CONFLICT_ERR: &str = "\
error: The argument '--flag...' cannot be used with '-F'
@ -289,6 +291,7 @@ For more information try '--help'
}
#[test]
#[cfg(feature = "error-context")]
fn conflict_output_rev() {
static CONFLICT_ERR_REV: &str = "\
error: The argument '-F' cannot be used with '--flag...'
@ -307,6 +310,7 @@ For more information try '--help'
}
#[test]
#[cfg(feature = "error-context")]
fn conflict_output_with_required() {
static CONFLICT_ERR: &str = "\
error: The argument '--flag...' cannot be used with '-F'
@ -325,6 +329,7 @@ For more information try '--help'
}
#[test]
#[cfg(feature = "error-context")]
fn conflict_output_rev_with_required() {
static CONFLICT_ERR_REV: &str = "\
error: The argument '-F' cannot be used with '--flag...'
@ -343,6 +348,7 @@ For more information try '--help'
}
#[test]
#[cfg(feature = "error-context")]
fn conflict_output_three_conflicting() {
static CONFLICT_ERR_THREE: &str = "\
error: The argument '--one' cannot be used with:
@ -382,6 +388,7 @@ For more information try '--help'
}
#[test]
#[cfg(feature = "error-context")]
fn two_conflicting_arguments() {
let a = Command::new("two_conflicting_arguments")
.arg(
@ -409,6 +416,7 @@ fn two_conflicting_arguments() {
}
#[test]
#[cfg(feature = "error-context")]
fn three_conflicting_arguments() {
let a = Command::new("three_conflicting_arguments")
.arg(

View file

@ -260,6 +260,7 @@ fn delimited_missing_value() {
#[cfg(debug_assertions)]
#[test]
#[cfg(feature = "error-context")]
#[should_panic = "Argument `arg`'s default_missing_value=\"value\" failed validation: error: \"value\" isn't a valid value for '[arg]'"]
fn default_missing_values_are_possible_values() {
use clap::{Arg, Command};
@ -275,6 +276,7 @@ fn default_missing_values_are_possible_values() {
#[cfg(debug_assertions)]
#[test]
#[cfg(feature = "error-context")]
#[should_panic = "Argument `arg`'s default_missing_value=\"value\" failed validation: error: Invalid value \"value\" for '[arg]"]
fn default_missing_values_are_valid() {
use clap::{Arg, Command};

View file

@ -1,9 +1,13 @@
use std::ffi::OsStr;
use std::ffi::OsString;
use super::utils;
use clap::builder::ArgPredicate;
use clap::{arg, error::ErrorKind, value_parser, Arg, ArgAction, Command};
#[cfg(feature = "error-context")]
use clap::error::ErrorKind;
use clap::{arg, value_parser, Arg, ArgAction, Command};
#[cfg(feature = "error-context")]
use super::utils;
#[test]
fn opts() {
@ -30,6 +34,7 @@ fn default_has_index() {
}
#[test]
#[cfg(feature = "error-context")]
fn opt_without_value_fail() {
let r = Command::new("df")
.arg(
@ -694,6 +699,7 @@ fn multiple_defaults_override() {
}
#[test]
#[cfg(feature = "error-context")]
fn default_vals_donnot_show_in_smart_usage() {
let cmd = Command::new("bug")
.arg(
@ -773,6 +779,7 @@ fn required_args_with_default_values() {
#[cfg(debug_assertions)]
#[test]
#[cfg(feature = "error-context")]
#[should_panic = "Argument `arg`'s default_value=\"value\" failed validation: error: \"value\" isn't a valid value for '[arg]'"]
fn default_values_are_possible_values() {
use clap::{Arg, Command};
@ -788,6 +795,7 @@ fn default_values_are_possible_values() {
#[cfg(debug_assertions)]
#[test]
#[cfg(feature = "error-context")]
#[should_panic = "Argument `arg`'s default_value=\"one\" failed validation: error: Invalid value \"one\" for '[arg]"]
fn invalid_default_values() {
use clap::{Arg, Command};
@ -817,6 +825,7 @@ fn valid_delimited_default_values() {
#[cfg(debug_assertions)]
#[test]
#[cfg(feature = "error-context")]
#[should_panic = "Argument `arg`'s default_value=\"one\" failed validation: error: Invalid value \"one\" for '[arg]"]
fn invalid_delimited_default_values() {
use clap::{Arg, Command};

View file

@ -10,24 +10,6 @@ Options:
-h, --help Print help information
";
static ONLY_B_ERROR: &str = "\
error: The following required arguments were not provided:
-c
Usage: prog -b -c
For more information try '--help'
";
static ONLY_C_ERROR: &str = "\
error: The following required arguments were not provided:
-b
Usage: prog -c -b
For more information try '--help'
";
fn cmd() -> Command {
Command::new("prog")
.arg(
@ -74,13 +56,32 @@ fn help_text() {
}
#[test]
#[cfg(feature = "error-context")]
fn no_duplicate_error() {
static ONLY_B_ERROR: &str = "\
error: The following required arguments were not provided:
-c
Usage: prog -b -c
For more information try '--help'
";
let res = cmd().try_get_matches_from(vec!["", "-b"]);
assert!(res.is_err());
let err = res.unwrap_err();
assert_eq!(err.kind(), ErrorKind::MissingRequiredArgument);
assert_eq!(err.to_string(), ONLY_B_ERROR);
static ONLY_C_ERROR: &str = "\
error: The following required arguments were not provided:
-b
Usage: prog -c -b
For more information try '--help'
";
let res = cmd().try_get_matches_from(vec!["", "-c"]);
assert!(res.is_err());
let err = res.unwrap_err();

View file

@ -1,7 +1,8 @@
use super::utils;
use clap::{error::ErrorKind, Arg, ArgAction, Command};
#[cfg(feature = "error-context")]
use super::utils;
#[test]
fn empty_values() {
let m = Command::new("config")
@ -102,6 +103,7 @@ fn no_empty_values_without_equals() {
}
#[test]
#[cfg(feature = "error-context")]
fn no_empty_values_without_equals_but_requires_equals() {
let cmd = Command::new("config").arg(
Arg::new("config")

View file

@ -97,6 +97,7 @@ Options:
}
#[test]
#[cfg(feature = "error-context")]
fn raw_prints_help() {
let cmd = Command::new("test");
let res = cmd
@ -130,6 +131,7 @@ error: Found an argument which wasn't expected or isn't valid in this context
}
#[test]
#[cfg(feature = "error-context")]
fn rich_formats_validation_error() {
let cmd = Command::new("test");
let res = cmd.try_get_matches_from(["test", "unused"]);
@ -147,6 +149,7 @@ For more information try '--help'
}
#[test]
#[cfg(feature = "error-context")]
fn raw_formats_validation_error() {
let cmd = Command::new("test");
let res = cmd

View file

@ -1,15 +1,7 @@
use super::utils;
use clap::{arg, Arg, ArgAction, Command};
const USE_FLAG_AS_ARGUMENT: &str = "\
error: Found argument '--another-flag' which wasn't expected, or isn't valid in this context
If you tried to supply `--another-flag` as a value rather than a flag, use `-- --another-flag`
Usage: mycat [OPTIONS] [filename]
For more information try '--help'
";
#[cfg(feature = "error-context")]
use super::utils;
#[test]
fn flag_using_short() {
@ -143,7 +135,18 @@ fn multiple_flags_in_single() {
}
#[test]
#[cfg(feature = "error-context")]
fn issue_1284_argument_in_flag_style() {
const USE_FLAG_AS_ARGUMENT: &str = "\
error: Found argument '--another-flag' which wasn't expected, or isn't valid in this context
If you tried to supply `--another-flag` as a value rather than a flag, use `-- --another-flag`
Usage: mycat [OPTIONS] [filename]
For more information try '--help'
";
let cmd = Command::new("mycat")
.arg(Arg::new("filename"))
.arg(Arg::new("a-flag").long("a-flag").action(ArgAction::SetTrue));
@ -176,6 +179,7 @@ fn issue_1284_argument_in_flag_style() {
}
#[test]
#[cfg(feature = "error-context")]
fn issue_2308_multiple_dashes() {
static MULTIPLE_DASHES: &str = "\
error: Found argument '-----' which wasn't expected, or isn't valid in this context

View file

@ -1,30 +1,6 @@
use super::utils;
use clap::{arg, error::ErrorKind, Arg, ArgAction, ArgGroup, Command, Id};
static REQ_GROUP_USAGE: &str = "error: The following required arguments were not provided:
<base|--delete>
Usage: clap-test <base|--delete>
For more information try '--help'
";
static REQ_GROUP_CONFLICT_USAGE: &str = "\
error: The argument '--delete' cannot be used with '[base]'
Usage: clap-test <base|--delete>
For more information try '--help'
";
static REQ_GROUP_CONFLICT_ONLY_OPTIONS: &str = "\
error: The argument '--delete' cannot be used with '--all'
Usage: clap-test <--all|--delete>
For more information try '--help'
";
use super::utils;
#[test]
fn required_group_missing_arg() {
@ -150,7 +126,16 @@ fn empty_group() {
}
#[test]
#[cfg(feature = "error-context")]
fn req_group_usage_string() {
static REQ_GROUP_USAGE: &str = "error: The following required arguments were not provided:
<base|--delete>
Usage: clap-test <base|--delete>
For more information try '--help'
";
let cmd = Command::new("req_group")
.arg(arg!([base] "Base commit"))
.arg(arg!(
@ -166,7 +151,16 @@ fn req_group_usage_string() {
}
#[test]
#[cfg(feature = "error-context")]
fn req_group_with_conflict_usage_string() {
static REQ_GROUP_CONFLICT_USAGE: &str = "\
error: The argument '--delete' cannot be used with '[base]'
Usage: clap-test <base|--delete>
For more information try '--help'
";
let cmd = Command::new("req_group")
.arg(arg!([base] "Base commit").conflicts_with("delete"))
.arg(arg!(
@ -187,7 +181,16 @@ fn req_group_with_conflict_usage_string() {
}
#[test]
#[cfg(feature = "error-context")]
fn req_group_with_conflict_usage_string_only_options() {
static REQ_GROUP_CONFLICT_ONLY_OPTIONS: &str = "\
error: The argument '--delete' cannot be used with '--all'
Usage: clap-test <--all|--delete>
For more information try '--help'
";
let cmd = Command::new("req_group")
.arg(arg!(-a --all "All").conflicts_with("delete"))
.arg(arg!(

View file

@ -1,7 +1,7 @@
use super::utils;
use clap::{arg, builder::PossibleValue, error::ErrorKind, Arg, ArgAction, ArgGroup, Command};
use super::utils;
fn setup() -> Command {
Command::new("test")
.author("Kevin K.")
@ -52,6 +52,7 @@ fn help_subcommand() {
}
#[test]
#[cfg(feature = "error-context")]
fn help_multi_subcommand_error() {
let cmd = Command::new("ctest").subcommand(
Command::new("subcmd").subcommand(

View file

@ -1,32 +1,7 @@
use super::utils;
use clap::{arg, error::ErrorKind, Arg, ArgAction, ArgMatches, Command};
#[cfg(feature = "suggestions")]
static DYM: &str = "\
error: Found argument '--optio' which wasn't expected, or isn't valid in this context
Did you mean '--option'?
If you tried to supply `--optio` as a value rather than a flag, use `-- --optio`
Usage: clap-test --option <opt>... [positional] [positional2] [positional3]...
For more information try '--help'
";
#[cfg(feature = "suggestions")]
static DYM_ISSUE_1073: &str = "\
error: Found argument '--files-without-matches' which wasn't expected, or isn't valid in this context
Did you mean '--files-without-match'?
If you tried to supply `--files-without-matches` as a value rather than a flag, use `-- --files-without-matches`
Usage: ripgrep-616 --files-without-match
For more information try '--help'
";
#[cfg(feature = "error-context")]
use super::utils;
#[test]
fn require_equals_fail() {
@ -44,6 +19,7 @@ fn require_equals_fail() {
}
#[test]
#[cfg(feature = "error-context")]
fn require_equals_fail_message() {
static NO_EQUALS: &str =
"error: Equal sign is needed when assigning values to '--config=<cfg>'.
@ -468,7 +444,20 @@ fn leading_hyphen_with_only_pos_follows() {
#[test]
#[cfg(feature = "suggestions")]
#[cfg(feature = "error-context")]
fn did_you_mean() {
static DYM: &str = "\
error: Found argument '--optio' which wasn't expected, or isn't valid in this context
Did you mean '--option'?
If you tried to supply `--optio` as a value rather than a flag, use `-- --optio`
Usage: clap-test --option <opt>... [positional] [positional2] [positional3]...
For more information try '--help'
";
utils::assert_output(utils::complex_app(), "clap-test --optio=foo", DYM, true);
}
@ -555,7 +544,20 @@ fn issue_1105_empty_value_short_explicit_no_space() {
#[test]
#[cfg(feature = "suggestions")]
#[cfg(feature = "error-context")]
fn issue_1073_suboptimal_flag_suggestion() {
static DYM_ISSUE_1073: &str = "\
error: Found argument '--files-without-matches' which wasn't expected, or isn't valid in this context
Did you mean '--files-without-match'?
If you tried to supply `--files-without-matches` as a value rather than a flag, use `-- --files-without-matches`
Usage: ripgrep-616 --files-without-match
For more information try '--help'
";
let cmd = Command::new("ripgrep-616")
.arg(
Arg::new("files-with-matches")

View file

@ -1,42 +1,7 @@
use super::utils;
use clap::{builder::PossibleValue, error::ErrorKind, Arg, ArgAction, Command};
#[cfg(feature = "suggestions")]
static PV_ERROR: &str = "\
error: \"slo\" isn't a valid value for '-O <option>'
[possible values: slow, fast, \"ludicrous speed\"]
Did you mean \"slow\"?
For more information try '--help'
";
#[cfg(not(feature = "suggestions"))]
static PV_ERROR: &str = "\
error: \"slo\" isn't a valid value for '-O <option>'
[possible values: slow, fast, \"ludicrous speed\"]
For more information try '--help'
";
#[cfg(feature = "suggestions")]
static PV_ERROR_ESCAPED: &str = "\
error: \"ludicrous\" isn't a valid value for '-O <option>'
[possible values: slow, fast, \"ludicrous speed\"]
Did you mean \"ludicrous speed\"?
For more information try '--help'
";
#[cfg(not(feature = "suggestions"))]
static PV_ERROR_ESCAPED: &str = "\
error: \"ludicrous\" isn't a valid value for '-O <option>'
[possible values: slow, fast, \"ludicrous speed\"]
For more information try '--help'
";
#[cfg(feature = "error-context")]
use super::utils;
#[test]
fn possible_values_of_positional() {
@ -209,7 +174,26 @@ fn possible_values_of_option_multiple_fail() {
}
#[test]
#[cfg(feature = "error-context")]
fn possible_values_output() {
#[cfg(feature = "suggestions")]
static PV_ERROR: &str = "\
error: \"slo\" isn't a valid value for '-O <option>'
[possible values: slow, fast, \"ludicrous speed\"]
Did you mean \"slow\"?
For more information try '--help'
";
#[cfg(not(feature = "suggestions"))]
static PV_ERROR: &str = "\
error: \"slo\" isn't a valid value for '-O <option>'
[possible values: slow, fast, \"ludicrous speed\"]
For more information try '--help'
";
utils::assert_output(
Command::new("test").arg(
Arg::new("option")
@ -224,7 +208,26 @@ fn possible_values_output() {
}
#[test]
#[cfg(feature = "error-context")]
fn possible_values_alias_output() {
#[cfg(feature = "suggestions")]
static PV_ERROR: &str = "\
error: \"slo\" isn't a valid value for '-O <option>'
[possible values: slow, fast, \"ludicrous speed\"]
Did you mean \"slow\"?
For more information try '--help'
";
#[cfg(not(feature = "suggestions"))]
static PV_ERROR: &str = "\
error: \"slo\" isn't a valid value for '-O <option>'
[possible values: slow, fast, \"ludicrous speed\"]
For more information try '--help'
";
utils::assert_output(
Command::new("test").arg(
Arg::new("option")
@ -243,7 +246,26 @@ fn possible_values_alias_output() {
}
#[test]
#[cfg(feature = "error-context")]
fn possible_values_hidden_output() {
#[cfg(feature = "suggestions")]
static PV_ERROR: &str = "\
error: \"slo\" isn't a valid value for '-O <option>'
[possible values: slow, fast, \"ludicrous speed\"]
Did you mean \"slow\"?
For more information try '--help'
";
#[cfg(not(feature = "suggestions"))]
static PV_ERROR: &str = "\
error: \"slo\" isn't a valid value for '-O <option>'
[possible values: slow, fast, \"ludicrous speed\"]
For more information try '--help'
";
utils::assert_output(
Command::new("test").arg(
Arg::new("option")
@ -263,7 +285,26 @@ fn possible_values_hidden_output() {
}
#[test]
#[cfg(feature = "error-context")]
fn escaped_possible_values_output() {
#[cfg(feature = "suggestions")]
static PV_ERROR_ESCAPED: &str = "\
error: \"ludicrous\" isn't a valid value for '-O <option>'
[possible values: slow, fast, \"ludicrous speed\"]
Did you mean \"ludicrous speed\"?
For more information try '--help'
";
#[cfg(not(feature = "suggestions"))]
static PV_ERROR_ESCAPED: &str = "\
error: \"ludicrous\" isn't a valid value for '-O <option>'
[possible values: slow, fast, \"ludicrous speed\"]
For more information try '--help'
";
utils::assert_output(
Command::new("test").arg(
Arg::new("option")
@ -278,7 +319,15 @@ fn escaped_possible_values_output() {
}
#[test]
#[cfg(feature = "error-context")]
fn missing_possible_value_error() {
static MISSING_PV_ERROR: &str = "\
error: The argument '-O <option>' requires a value but none was supplied
[possible values: slow, fast, \"ludicrous speed\"]
For more information try '--help'
";
utils::assert_output(
Command::new("test").arg(
Arg::new("option")
@ -297,13 +346,6 @@ fn missing_possible_value_error() {
);
}
static MISSING_PV_ERROR: &str = "\
error: The argument '-O <option>' requires a value but none was supplied
[possible values: slow, fast, \"ludicrous speed\"]
For more information try '--help'
";
#[test]
fn alias() {
let m = Command::new("pv")

View file

@ -1,54 +1,8 @@
use super::utils;
use clap::builder::ArgPredicate;
use clap::{arg, error::ErrorKind, Arg, ArgAction, ArgGroup, Command};
static REQUIRE_EQUALS: &str = "\
error: The following required arguments were not provided:
--opt=<FILE>
Usage: clap-test --opt=<FILE>
For more information try '--help'
";
static REQUIRE_EQUALS_FILTERED: &str = "\
error: The following required arguments were not provided:
--opt=<FILE>
Usage: clap-test --opt=<FILE> --foo=<FILE>
For more information try '--help'
";
static REQUIRE_EQUALS_FILTERED_GROUP: &str = "\
error: The following required arguments were not provided:
--opt=<FILE>
Usage: clap-test --opt=<FILE> --foo=<FILE> <--g1=<FILE>|--g2=<FILE>>
For more information try '--help'
";
static MISSING_REQ: &str = "\
error: The following required arguments were not provided:
--long-option-2 <option2>
<positional>
<positional2>
Usage: clap-test --long-option-2 <option2> -F <positional> <positional2> [positional3]...
For more information try '--help'
";
static COND_REQ_IN_USAGE: &str = "\
error: The following required arguments were not provided:
--output <output>
Usage: test --target <target> --input <input> --output <output>
For more information try '--help'
";
#[cfg(feature = "error-context")]
use super::utils;
#[test]
fn flag_required() {
@ -127,16 +81,9 @@ fn positional_required_2() {
}
#[test]
#[cfg(feature = "error-context")]
fn positional_required_with_requires() {
let cmd = Command::new("positional_required")
.arg(Arg::new("flag").required(true).requires("opt"))
.arg(Arg::new("opt"))
.arg(Arg::new("bar"));
utils::assert_output(cmd, "clap-test", POSITIONAL_REQ, true);
}
static POSITIONAL_REQ: &str = "\
static POSITIONAL_REQ: &str = "\
error: The following required arguments were not provided:
<flag>
<opt>
@ -146,17 +93,18 @@ Usage: clap-test <flag> <opt> [bar]
For more information try '--help'
";
#[test]
fn positional_required_with_requires_if_no_value() {
let cmd = Command::new("positional_required")
.arg(Arg::new("flag").required(true).requires_if("val", "opt"))
.arg(Arg::new("flag").required(true).requires("opt"))
.arg(Arg::new("opt"))
.arg(Arg::new("bar"));
utils::assert_output(cmd, "clap-test", POSITIONAL_REQ_IF_NO_VAL, true);
utils::assert_output(cmd, "clap-test", POSITIONAL_REQ, true);
}
static POSITIONAL_REQ_IF_NO_VAL: &str = "\
#[test]
#[cfg(feature = "error-context")]
fn positional_required_with_requires_if_no_value() {
static POSITIONAL_REQ_IF_NO_VAL: &str = "\
error: The following required arguments were not provided:
<flag>
@ -165,18 +113,18 @@ Usage: clap-test <flag> [opt] [bar]
For more information try '--help'
";
#[test]
fn positional_required_with_requires_if_value() {
let cmd = Command::new("positional_required")
.arg(Arg::new("flag").required(true).requires_if("val", "opt"))
.arg(Arg::new("foo").required(true))
.arg(Arg::new("opt"))
.arg(Arg::new("bar"));
utils::assert_output(cmd, "clap-test val", POSITIONAL_REQ_IF_VAL, true);
utils::assert_output(cmd, "clap-test", POSITIONAL_REQ_IF_NO_VAL, true);
}
static POSITIONAL_REQ_IF_VAL: &str = "\
#[test]
#[cfg(feature = "error-context")]
fn positional_required_with_requires_if_value() {
static POSITIONAL_REQ_IF_VAL: &str = "\
error: The following required arguments were not provided:
<foo>
<opt>
@ -186,6 +134,15 @@ Usage: clap-test <flag> <foo> <opt> [bar]
For more information try '--help'
";
let cmd = Command::new("positional_required")
.arg(Arg::new("flag").required(true).requires_if("val", "opt"))
.arg(Arg::new("foo").required(true))
.arg(Arg::new("opt"))
.arg(Arg::new("bar"));
utils::assert_output(cmd, "clap-test val", POSITIONAL_REQ_IF_VAL, true);
}
#[test]
fn group_required() {
let result = Command::new("group_required")
@ -553,7 +510,19 @@ fn required_unless_any_err() {
}
#[test]
#[cfg(feature = "error-context")]
fn missing_required_output() {
static MISSING_REQ: &str = "\
error: The following required arguments were not provided:
--long-option-2 <option2>
<positional>
<positional2>
Usage: clap-test --long-option-2 <option2> -F <positional> <positional2> [positional3]...
For more information try '--help'
";
utils::assert_output(utils::complex_app(), "clap-test -F", MISSING_REQ, true);
}
@ -786,7 +755,17 @@ fn required_if_any_all_values_present_fail() {
}
#[test]
#[cfg(feature = "error-context")]
fn list_correct_required_args() {
static COND_REQ_IN_USAGE: &str = "\
error: The following required arguments were not provided:
--output <output>
Usage: test --target <target> --input <input> --output <output>
For more information try '--help'
";
let cmd = Command::new("Test cmd")
.version("1.0")
.author("F0x06")
@ -820,7 +799,17 @@ fn list_correct_required_args() {
}
#[test]
#[cfg(feature = "error-context")]
fn required_if_val_present_fail_error_output() {
static COND_REQ_IN_USAGE: &str = "\
error: The following required arguments were not provided:
--output <output>
Usage: test --target <target> --input <input> --output <output>
For more information try '--help'
";
let cmd = Command::new("Test cmd")
.version("1.0")
.author("F0x06")
@ -935,7 +924,17 @@ fn required_ifs_wrong_val_mult_fail() {
}
#[test]
#[cfg(feature = "error-context")]
fn require_eq() {
static REQUIRE_EQUALS: &str = "\
error: The following required arguments were not provided:
--opt=<FILE>
Usage: clap-test --opt=<FILE>
For more information try '--help'
";
let cmd = Command::new("clap-test").version("v1.4.8").arg(
Arg::new("opt")
.long("opt")
@ -949,7 +948,17 @@ fn require_eq() {
}
#[test]
#[cfg(feature = "error-context")]
fn require_eq_filtered() {
static REQUIRE_EQUALS_FILTERED: &str = "\
error: The following required arguments were not provided:
--opt=<FILE>
Usage: clap-test --opt=<FILE> --foo=<FILE>
For more information try '--help'
";
let cmd = Command::new("clap-test")
.version("v1.4.8")
.arg(
@ -974,7 +983,17 @@ fn require_eq_filtered() {
}
#[test]
#[cfg(feature = "error-context")]
fn require_eq_filtered_group() {
static REQUIRE_EQUALS_FILTERED_GROUP: &str = "\
error: The following required arguments were not provided:
--opt=<FILE>
Usage: clap-test --opt=<FILE> --foo=<FILE> <--g1=<FILE>|--g2=<FILE>>
For more information try '--help'
";
let cmd = Command::new("clap-test")
.version("v1.4.8")
.arg(
@ -1020,17 +1039,6 @@ fn require_eq_filtered_group() {
);
}
static ISSUE_1158: &str = "\
error: The following required arguments were not provided:
-x <X>
-y <Y>
-z <Z>
Usage: example -x <X> -y <Y> -z <Z> <ID>
For more information try '--help'
";
fn issue_1158_app() -> Command {
Command::new("example")
.arg(
@ -1054,6 +1062,7 @@ fn issue_1158_app() -> Command {
}
#[test]
#[cfg(feature = "error-context")]
fn multiple_required_unless_usage_printing() {
static MULTIPLE_REQUIRED_UNLESS_USAGE: &str = "\
error: The following required arguments were not provided:
@ -1097,7 +1106,19 @@ For more information try '--help'
}
#[test]
#[cfg(feature = "error-context")]
fn issue_1158_conflicting_requirements() {
static ISSUE_1158: &str = "\
error: The following required arguments were not provided:
-x <X>
-y <Y>
-z <Z>
Usage: example -x <X> -y <Y> -z <Z> <ID>
For more information try '--help'
";
let cmd = issue_1158_app();
utils::assert_output(cmd, "example id", ISSUE_1158, true);
@ -1409,6 +1430,7 @@ fn required_unless_all_on_default_value() {
}
#[test]
#[cfg(feature = "error-context")]
fn required_error_doesnt_duplicate() {
let cmd = Command::new("Clap-created-USAGE-string-bug")
.arg(Arg::new("a").required(true))
@ -1435,6 +1457,7 @@ For more information try '--help'
}
#[test]
#[cfg(feature = "error-context")]
fn required_require_with_group_shows_flag() {
let cmd = Command::new("test")
.arg(arg!(--"require-first").requires("first"))

View file

@ -1,66 +1,6 @@
use super::utils;
use clap::{arg, error::ErrorKind, Arg, ArgAction, Command};
static VISIBLE_ALIAS_HELP: &str = "\
Usage: clap-test [COMMAND]
Commands:
test Some help [aliases: dongle, done]
help Print this message or the help of the given subcommand(s)
Options:
-h, --help Print help information
-V, --version Print version information
";
static INVISIBLE_ALIAS_HELP: &str = "\
Usage: clap-test [COMMAND]
Commands:
test Some help
help Print this message or the help of the given subcommand(s)
Options:
-h, --help Print help information
-V, --version Print version information
";
#[cfg(feature = "suggestions")]
static DYM_SUBCMD: &str = "\
error: The subcommand 'subcm' wasn't recognized
Did you mean 'subcmd'?
If you believe you received this message in error, try re-running with 'dym -- subcm'
Usage: dym [COMMAND]
For more information try '--help'
";
#[cfg(feature = "suggestions")]
static DYM_SUBCMD_AMBIGUOUS: &str = "\
error: The subcommand 'te' wasn't recognized
Did you mean 'test' or 'temp'?
If you believe you received this message in error, try re-running with 'dym -- te'
Usage: dym [COMMAND]
For more information try '--help'
";
static SUBCMD_AFTER_DOUBLE_DASH: &str = "\
error: Found argument 'subcmd' which wasn't expected, or isn't valid in this context
If you tried to supply `subcmd` as a subcommand, remove the '--' before it.
Usage: cmd [COMMAND]
For more information try '--help'
";
use super::utils;
#[test]
fn subcommand() {
@ -154,14 +94,42 @@ fn multiple_aliases() {
#[test]
#[cfg(feature = "suggestions")]
#[cfg(feature = "error-context")]
fn subcmd_did_you_mean_output() {
#[cfg(feature = "suggestions")]
static DYM_SUBCMD: &str = "\
error: The subcommand 'subcm' wasn't recognized
Did you mean 'subcmd'?
If you believe you received this message in error, try re-running with 'dym -- subcm'
Usage: dym [COMMAND]
For more information try '--help'
";
let cmd = Command::new("dym").subcommand(Command::new("subcmd"));
utils::assert_output(cmd, "dym subcm", DYM_SUBCMD, true);
}
#[test]
#[cfg(feature = "suggestions")]
#[cfg(feature = "error-context")]
fn subcmd_did_you_mean_output_ambiguous() {
#[cfg(feature = "suggestions")]
static DYM_SUBCMD_AMBIGUOUS: &str = "\
error: The subcommand 'te' wasn't recognized
Did you mean 'test' or 'temp'?
If you believe you received this message in error, try re-running with 'dym -- te'
Usage: dym [COMMAND]
For more information try '--help'
";
let cmd = Command::new("dym")
.subcommand(Command::new("test"))
.subcommand(Command::new("temp"));
@ -170,6 +138,7 @@ fn subcmd_did_you_mean_output_ambiguous() {
#[test]
#[cfg(feature = "suggestions")]
#[cfg(feature = "error-context")]
fn subcmd_did_you_mean_output_arg() {
static EXPECTED: &str = "\
error: Found argument '--subcmarg' which wasn't expected, or isn't valid in this context
@ -191,6 +160,7 @@ For more information try '--help'
#[test]
#[cfg(feature = "suggestions")]
#[cfg(feature = "error-context")]
fn subcmd_did_you_mean_output_arg_false_positives() {
static EXPECTED: &str = "\
error: Found argument '--subcmarg' which wasn't expected, or isn't valid in this context
@ -219,6 +189,18 @@ fn alias_help() {
#[test]
fn visible_aliases_help_output() {
static VISIBLE_ALIAS_HELP: &str = "\
Usage: clap-test [COMMAND]
Commands:
test Some help [aliases: dongle, done]
help Print this message or the help of the given subcommand(s)
Options:
-h, --help Print help information
-V, --version Print version information
";
let cmd = Command::new("clap-test").version("2.6").subcommand(
Command::new("test")
.about("Some help")
@ -231,6 +213,18 @@ fn visible_aliases_help_output() {
#[test]
fn invisible_aliases_help_output() {
static INVISIBLE_ALIAS_HELP: &str = "\
Usage: clap-test [COMMAND]
Commands:
test Some help
help Print this message or the help of the given subcommand(s)
Options:
-h, --help Print help information
-V, --version Print version information
";
let cmd = Command::new("clap-test")
.version("2.6")
.subcommand(Command::new("test").about("Some help").alias("invisible"));
@ -361,7 +355,18 @@ fn subcommand_placeholder_test() {
}
#[test]
#[cfg(feature = "error-context")]
fn subcommand_used_after_double_dash() {
static SUBCMD_AFTER_DOUBLE_DASH: &str = "\
error: Found argument 'subcmd' which wasn't expected, or isn't valid in this context
If you tried to supply `subcmd` as a subcommand, remove the '--' before it.
Usage: cmd [COMMAND]
For more information try '--help'
";
let cmd = Command::new("cmd").subcommand(Command::new("subcmd"));
utils::assert_output(cmd, "cmd -- subcmd", SUBCMD_AFTER_DOUBLE_DASH, true);
@ -421,6 +426,7 @@ fn issue_2494_subcommand_is_present() {
}
#[test]
#[cfg(feature = "error-context")]
fn subcommand_not_recognized() {
let cmd = Command::new("fake")
.subcommand(Command::new("sub"))
@ -494,6 +500,7 @@ fn hostname_like_multicall() {
}
#[test]
#[cfg(feature = "error-context")]
fn bad_multicall_command_error() {
let cmd = Command::new("repl")
.version("1.0.0")

View file

@ -68,6 +68,7 @@ struct HexOpt {
}
#[test]
#[cfg(feature = "error-context")]
fn test_parse_hex() {
assert_eq!(
HexOpt { number: 5 },

View file

@ -136,6 +136,7 @@ struct HexOpt {
}
#[test]
#[cfg(feature = "error-context")]
fn test_parse_hex_function_path() {
assert_eq!(
HexOpt { number: 5 },

View file

@ -1,6 +1,7 @@
#![cfg(not(tarpaulin))]
#[test]
#[cfg(feature = "error-context")]
fn example_tests() {
let t = trycmd::TestCases::new();
let features = [

View file

@ -1,6 +1,7 @@
#![cfg(not(tarpaulin))]
#[test]
#[cfg(feature = "error-context")]
fn ui_tests() {
let t = trycmd::TestCases::new();
let features = [