mirror of
https://github.com/clap-rs/clap
synced 2024-12-13 14:22:34 +00:00
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:
parent
b4788d51f1
commit
2d83a7b12e
24 changed files with 568 additions and 348 deletions
|
@ -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)
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 => {
|
||||
|
|
240
src/error/mod.rs
240
src/error/mod.rs
|
@ -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> {
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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!(
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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"))
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -68,6 +68,7 @@ struct HexOpt {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "error-context")]
|
||||
fn test_parse_hex() {
|
||||
assert_eq!(
|
||||
HexOpt { number: 5 },
|
||||
|
|
|
@ -136,6 +136,7 @@ struct HexOpt {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "error-context")]
|
||||
fn test_parse_hex_function_path() {
|
||||
assert_eq!(
|
||||
HexOpt { number: 5 },
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#![cfg(not(tarpaulin))]
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "error-context")]
|
||||
fn example_tests() {
|
||||
let t = trycmd::TestCases::new();
|
||||
let features = [
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#![cfg(not(tarpaulin))]
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "error-context")]
|
||||
fn ui_tests() {
|
||||
let t = trycmd::TestCases::new();
|
||||
let features = [
|
||||
|
|
Loading…
Reference in a new issue