1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-29 12:07:46 +00:00

Merge branch 'main' of github.com:uutils/coreutils into hbina-test_ls_order_time-is-flaky

This commit is contained in:
Hanif Bin Ariffin 2022-02-03 19:57:13 +08:00
commit c4c666814b
22 changed files with 268 additions and 50 deletions

View file

@ -1,2 +1,11 @@
[target.x86_64-unknown-redox] [target.x86_64-unknown-redox]
linker = "x86_64-unknown-redox-gcc" linker = "x86_64-unknown-redox-gcc"
[target.'cfg(feature = "cargo-clippy")']
rustflags = [
"-Wclippy::use_self",
"-Wclippy::needless_pass_by_value",
"-Wclippy::semicolon_if_nothing_returned",
"-Wclippy::single_char_pattern",
"-Wclippy::explicit_iter_loop",
]

View file

@ -87,7 +87,7 @@ fn main() {
}; };
if util == "completion" { if util == "completion" {
gen_completions(args, utils); gen_completions(args, &utils);
} }
match utils.get(util) { match utils.get(util) {
@ -132,7 +132,7 @@ fn main() {
/// Prints completions for the utility in the first parameter for the shell in the second parameter to stdout /// Prints completions for the utility in the first parameter for the shell in the second parameter to stdout
fn gen_completions<T: uucore::Args>( fn gen_completions<T: uucore::Args>(
args: impl Iterator<Item = OsString>, args: impl Iterator<Item = OsString>,
util_map: UtilityMap<T>, util_map: &UtilityMap<T>,
) -> ! { ) -> ! {
let all_utilities: Vec<_> = std::iter::once("coreutils") let all_utilities: Vec<_> = std::iter::once("coreutils")
.chain(util_map.keys().copied()) .chain(util_map.keys().copied())
@ -168,9 +168,9 @@ fn gen_completions<T: uucore::Args>(
process::exit(0); process::exit(0);
} }
fn gen_coreutils_app<T: uucore::Args>(util_map: UtilityMap<T>) -> App<'static> { fn gen_coreutils_app<T: uucore::Args>(util_map: &UtilityMap<T>) -> App<'static> {
let mut app = App::new("coreutils"); let mut app = App::new("coreutils");
for (_, (_, sub_app)) in &util_map { for (_, (_, sub_app)) in util_map {
app = app.subcommand(sub_app()); app = app.subcommand(sub_app());
} }
app app

View file

@ -201,12 +201,12 @@ fn set_main_group(group: &str) -> UResult<()> {
} }
#[cfg(any(target_vendor = "apple", target_os = "freebsd"))] #[cfg(any(target_vendor = "apple", target_os = "freebsd"))]
fn set_groups(groups: Vec<libc::gid_t>) -> libc::c_int { fn set_groups(groups: &[libc::gid_t]) -> libc::c_int {
unsafe { setgroups(groups.len() as libc::c_int, groups.as_ptr()) } unsafe { setgroups(groups.len() as libc::c_int, groups.as_ptr()) }
} }
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
fn set_groups(groups: Vec<libc::gid_t>) -> libc::c_int { fn set_groups(groups: &[libc::gid_t]) -> libc::c_int {
unsafe { setgroups(groups.len() as libc::size_t, groups.as_ptr()) } unsafe { setgroups(groups.len() as libc::size_t, groups.as_ptr()) }
} }
@ -220,7 +220,7 @@ fn set_groups_from_str(groups: &str) -> UResult<()> {
}; };
groups_vec.push(gid); groups_vec.push(gid);
} }
let err = set_groups(groups_vec); let err = set_groups(&groups_vec);
if err != 0 { if err != 0 {
return Err(ChrootError::SetGroupsFailed(Error::last_os_error()).into()); return Err(ChrootError::SetGroupsFailed(Error::last_os_error()).into());
} }

View file

@ -144,7 +144,7 @@ impl Stat {
#[cfg(windows)] #[cfg(windows)]
let file_info = get_file_info(&path); let file_info = get_file_info(&path);
#[cfg(windows)] #[cfg(windows)]
Ok(Stat { Ok(Self {
path, path,
is_dir: metadata.is_dir(), is_dir: metadata.is_dir(),
size: metadata.len(), size: metadata.len(),

View file

@ -104,6 +104,7 @@ fn load_config_file(opts: &mut Options) -> UResult<()> {
} }
#[cfg(not(windows))] #[cfg(not(windows))]
#[allow(clippy::ptr_arg)]
fn build_command<'a, 'b>(args: &'a mut Vec<&'b str>) -> (Cow<'b, str>, &'a [&'b str]) { fn build_command<'a, 'b>(args: &'a mut Vec<&'b str>) -> (Cow<'b, str>, &'a [&'b str]) {
let progname = Cow::from(args[0]); let progname = Cow::from(args[0]);
(progname, &args[1..]) (progname, &args[1..])

View file

@ -4,16 +4,62 @@
// * // *
// * For the full copyright and license information, please view the LICENSE // * For the full copyright and license information, please view the LICENSE
// * file that was distributed with this source code. // * file that was distributed with this source code.
use clap::{App, AppSettings, Arg};
use std::io::Write;
use uucore::error::{set_exit_code, UResult};
use clap::App; static ABOUT: &str = "\
use uucore::error::UResult; Returns false, an unsuccessful exit status.
Immediately returns with the exit status `1`. When invoked with one of the recognized options it
will try to write the help or version text. Any IO error during this operation is diagnosed, yet
the program will also return `1`.
";
#[uucore::main] #[uucore::main]
pub fn uumain(args: impl uucore::Args) -> UResult<()> { pub fn uumain(args: impl uucore::Args) -> UResult<()> {
uu_app().get_matches_from(args); let mut app = uu_app();
Err(1.into())
// Mirror GNU options, always return `1`. In particular even the 'successful' cases of no-op,
// and the interrupted display of help and version should return `1`. Also, we return Ok in all
// paths to avoid the allocation of an error object, an operation that could, in theory, fail
// and unwind through the standard library allocation handling machinery.
set_exit_code(1);
if let Ok(matches) = app.try_get_matches_from_mut(args) {
let error = if matches.index_of("help").is_some() {
app.print_long_help()
} else if matches.index_of("version").is_some() {
writeln!(std::io::stdout(), "{}", app.render_version())
} else {
Ok(())
};
// Try to display this error.
if let Err(print_fail) = error {
// Completely ignore any error here, no more failover and we will fail in any case.
let _ = writeln!(std::io::stderr(), "{}: {}", uucore::util_name(), print_fail);
}
}
Ok(())
} }
pub fn uu_app<'a>() -> App<'a> { pub fn uu_app<'a>() -> App<'a> {
App::new(uucore::util_name()) App::new(uucore::util_name())
.version(clap::crate_version!())
.about(ABOUT)
// We provide our own help and version options, to ensure maximum compatibility with GNU.
.setting(AppSettings::DisableHelpFlag | AppSettings::DisableVersionFlag)
.arg(
Arg::new("help")
.long("help")
.help("Print help information")
.exclusive(true),
)
.arg(
Arg::new("version")
.long("version")
.help("Print version information"),
)
} }

View file

@ -12,6 +12,7 @@ use libc::c_long;
use uucore::error::UResult; use uucore::error::UResult;
static SYNTAX: &str = "[options]"; static SYNTAX: &str = "[options]";
const SUMMARY: &str = "Print the numeric identifier (in hexadecimal) for the current host";
// currently rust libc interface doesn't include gethostid // currently rust libc interface doesn't include gethostid
extern "C" { extern "C" {
@ -28,6 +29,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
pub fn uu_app<'a>() -> App<'a> { pub fn uu_app<'a>() -> App<'a> {
App::new(uucore::util_name()) App::new(uucore::util_name())
.version(crate_version!()) .version(crate_version!())
.about(SUMMARY)
.override_usage(SYNTAX) .override_usage(SYNTAX)
.setting(AppSettings::InferLongArgs) .setting(AppSettings::InferLongArgs)
} }

View file

@ -74,7 +74,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
table(); table();
Ok(()) Ok(())
} }
Mode::List => list(pids_or_signals.get(0).cloned()), Mode::List => list(pids_or_signals.get(0)),
} }
} }
@ -168,9 +168,9 @@ fn print_signals() {
println!(); println!();
} }
fn list(arg: Option<String>) -> UResult<()> { fn list(arg: Option<&String>) -> UResult<()> {
match arg { match arg {
Some(ref x) => print_signal(x), Some(x) => print_signal(x),
None => { None => {
print_signals(); print_signals();
Ok(()) Ok(())

View file

@ -31,6 +31,7 @@ Write a random permutation of the input lines to standard output.
With no FILE, or when FILE is -, read standard input. With no FILE, or when FILE is -, read standard input.
"#; "#;
static ABOUT: &str = "Shuffle the input by outputting a random permutation of input lines. Each output permutation is equally likely.";
static TEMPLATE: &str = "Usage: {usage}\nMandatory arguments to long options are mandatory for short options too.\n{options}"; static TEMPLATE: &str = "Usage: {usage}\nMandatory arguments to long options are mandatory for short options too.\n{options}";
struct Options { struct Options {
@ -121,6 +122,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
pub fn uu_app<'a>() -> App<'a> { pub fn uu_app<'a>() -> App<'a> {
App::new(uucore::util_name()) App::new(uucore::util_name())
.name(NAME) .name(NAME)
.about(ABOUT)
.version(crate_version!()) .version(crate_version!())
.help_template(TEMPLATE) .help_template(TEMPLATE)
.override_usage(USAGE) .override_usage(USAGE)

View file

@ -96,8 +96,8 @@ impl Number {
#[allow(dead_code)] #[allow(dead_code)]
fn digits(&self) -> &Vec<u8> { fn digits(&self) -> &Vec<u8> {
match self { match self {
Number::FixedWidth(number) => &number.digits, Self::FixedWidth(number) => &number.digits,
Number::DynamicWidth(number) => &number.digits, Self::DynamicWidth(number) => &number.digits,
} }
} }
@ -136,8 +136,8 @@ impl Number {
/// ``` /// ```
pub fn increment(&mut self) -> Result<(), Overflow> { pub fn increment(&mut self) -> Result<(), Overflow> {
match self { match self {
Number::FixedWidth(number) => number.increment(), Self::FixedWidth(number) => number.increment(),
Number::DynamicWidth(number) => number.increment(), Self::DynamicWidth(number) => number.increment(),
} }
} }
} }
@ -145,8 +145,8 @@ impl Number {
impl Display for Number { impl Display for Number {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self { match self {
Number::FixedWidth(number) => number.fmt(f), Self::FixedWidth(number) => number.fmt(f),
Number::DynamicWidth(number) => number.fmt(f), Self::DynamicWidth(number) => number.fmt(f),
} }
} }
} }
@ -183,8 +183,8 @@ pub struct FixedWidthNumber {
impl FixedWidthNumber { impl FixedWidthNumber {
/// Instantiate a number of the given radix and width. /// Instantiate a number of the given radix and width.
pub fn new(radix: u8, width: usize) -> FixedWidthNumber { pub fn new(radix: u8, width: usize) -> Self {
FixedWidthNumber { Self {
radix, radix,
digits: vec![0; width], digits: vec![0; width],
} }
@ -286,8 +286,8 @@ impl DynamicWidthNumber {
/// ///
/// This associated function returns a new instance of the struct /// This associated function returns a new instance of the struct
/// with the given radix and a width of two digits, both 0. /// with the given radix and a width of two digits, both 0.
pub fn new(radix: u8) -> DynamicWidthNumber { pub fn new(radix: u8) -> Self {
DynamicWidthNumber { Self {
radix, radix,
digits: vec![0, 0], digits: vec![0, 0],
} }
@ -404,7 +404,7 @@ mod tests {
fn num(n: usize) -> Number { fn num(n: usize) -> Number {
let mut number = Number::DynamicWidth(DynamicWidthNumber::new(26)); let mut number = Number::DynamicWidth(DynamicWidthNumber::new(26));
for _ in 0..n { for _ in 0..n {
number.increment().unwrap() number.increment().unwrap();
} }
number number
} }
@ -428,7 +428,7 @@ mod tests {
fn num(n: usize) -> Number { fn num(n: usize) -> Number {
let mut number = Number::DynamicWidth(DynamicWidthNumber::new(10)); let mut number = Number::DynamicWidth(DynamicWidthNumber::new(10));
for _ in 0..n { for _ in 0..n {
number.increment().unwrap() number.increment().unwrap();
} }
number number
} }

View file

@ -62,7 +62,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
.override_usage(&usage[..]) .override_usage(&usage[..])
.after_help(&long_usage[..]) .after_help(&long_usage[..])
.get_matches_from(args); .get_matches_from(args);
let settings = Settings::from(matches)?; let settings = Settings::from(&matches)?;
split(&settings) split(&settings)
} }
@ -232,7 +232,7 @@ struct Settings {
impl Settings { impl Settings {
/// Parse a strategy from the command-line arguments. /// Parse a strategy from the command-line arguments.
fn from(matches: ArgMatches) -> UResult<Self> { fn from(matches: &ArgMatches) -> UResult<Self> {
let result = Self { let result = Self {
suffix_length: matches suffix_length: matches
.value_of(OPT_SUFFIX_LENGTH) .value_of(OPT_SUFFIX_LENGTH)
@ -242,7 +242,7 @@ impl Settings {
numeric_suffix: matches.occurrences_of(OPT_NUMERIC_SUFFIXES) > 0, numeric_suffix: matches.occurrences_of(OPT_NUMERIC_SUFFIXES) > 0,
additional_suffix: matches.value_of(OPT_ADDITIONAL_SUFFIX).unwrap().to_owned(), additional_suffix: matches.value_of(OPT_ADDITIONAL_SUFFIX).unwrap().to_owned(),
verbose: matches.occurrences_of("verbose") > 0, verbose: matches.occurrences_of("verbose") > 0,
strategy: Strategy::from(&matches)?, strategy: Strategy::from(matches)?,
input: matches.value_of(ARG_INPUT).unwrap().to_owned(), input: matches.value_of(ARG_INPUT).unwrap().to_owned(),
prefix: matches.value_of(ARG_PREFIX).unwrap().to_owned(), prefix: matches.value_of(ARG_PREFIX).unwrap().to_owned(),
filter: matches.value_of(OPT_FILTER).map(|s| s.to_owned()), filter: matches.value_of(OPT_FILTER).map(|s| s.to_owned()),

View file

@ -30,6 +30,7 @@ impl ProcessChecker {
} }
// Borrowing mutably to be aligned with Windows implementation // Borrowing mutably to be aligned with Windows implementation
#[allow(clippy::wrong_self_convention)]
pub fn is_dead(&mut self) -> bool { pub fn is_dead(&mut self) -> bool {
unsafe { libc::kill(self.pid, 0) != 0 && get_errno() != libc::EPERM } unsafe { libc::kill(self.pid, 0) != 0 && get_errno() != libc::EPERM }
} }

View file

@ -24,11 +24,11 @@ pub struct ProcessChecker {
} }
impl ProcessChecker { impl ProcessChecker {
pub fn new(process_id: self::Pid) -> ProcessChecker { pub fn new(process_id: self::Pid) -> Self {
#[allow(non_snake_case)] #[allow(non_snake_case)]
let FALSE = 0i32; let FALSE = 0i32;
let h = unsafe { OpenProcess(SYNCHRONIZE, FALSE, process_id as DWORD) }; let h = unsafe { OpenProcess(SYNCHRONIZE, FALSE, process_id as DWORD) };
ProcessChecker { Self {
dead: h.is_null(), dead: h.is_null(),
handle: h, handle: h,
} }

View file

@ -4,16 +4,59 @@
// * // *
// * For the full copyright and license information, please view the LICENSE // * For the full copyright and license information, please view the LICENSE
// * file that was distributed with this source code. // * file that was distributed with this source code.
use clap::{App, AppSettings, Arg};
use std::io::Write;
use uucore::error::{set_exit_code, UResult};
use clap::{App, AppSettings}; static ABOUT: &str = "\
use uucore::error::UResult; Returns true, a successful exit status.
Immediately returns with the exit status `0`, except when invoked with one of the recognized
options. In those cases it will try to write the help or version text. Any IO error during this
operation causes the program to return `1` instead.
";
#[uucore::main] #[uucore::main]
pub fn uumain(args: impl uucore::Args) -> UResult<()> { pub fn uumain(args: impl uucore::Args) -> UResult<()> {
uu_app().get_matches_from(args); let mut app = uu_app();
if let Ok(matches) = app.try_get_matches_from_mut(args) {
let error = if matches.index_of("help").is_some() {
app.print_long_help()
} else if matches.index_of("version").is_some() {
writeln!(std::io::stdout(), "{}", app.render_version())
} else {
Ok(())
};
if let Err(print_fail) = error {
// Try to display this error.
let _ = writeln!(std::io::stderr(), "{}: {}", uucore::util_name(), print_fail);
// Mirror GNU options. When failing to print warnings or version flags, then we exit
// with FAIL. This avoids allocation some error information which may result in yet
// other types of failure.
set_exit_code(1);
}
}
Ok(()) Ok(())
} }
pub fn uu_app<'a>() -> App<'a> { pub fn uu_app<'a>() -> App<'a> {
App::new(uucore::util_name()).setting(AppSettings::InferLongArgs) App::new(uucore::util_name())
.version(clap::crate_version!())
.about(ABOUT)
// We provide our own help and version options, to ensure maximum compatibility with GNU.
.setting(AppSettings::DisableHelpFlag | AppSettings::DisableVersionFlag)
.arg(
Arg::new("help")
.long("help")
.help("Print help information")
.exclusive(true),
)
.arg(
Arg::new("version")
.long("version")
.help("Print version information"),
)
} }

View file

@ -115,7 +115,14 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let matches = uu_app() let matches = uu_app()
.override_usage(&usage[..]) .override_usage(&usage[..])
.after_help(&long_usage[..]) .after_help(&long_usage[..])
.get_matches_from(args); .try_get_matches_from(args)
.map_err(|e| {
e.print().expect("Error writing clap::Error");
match e.kind {
clap::ErrorKind::DisplayHelp | clap::ErrorKind::DisplayVersion => 0,
_ => 1,
}
})?;
let files: Vec<String> = matches let files: Vec<String> = matches
.values_of(options::ARG_FILES) .values_of(options::ARG_FILES)

View file

@ -238,7 +238,7 @@ impl MountInfo {
} }
} }
#[cfg(windows)] #[cfg(windows)]
fn new(mut volume_name: String) -> Option<MountInfo> { fn new(mut volume_name: String) -> Option<Self> {
let mut dev_name_buf = [0u16; MAX_PATH]; let mut dev_name_buf = [0u16; MAX_PATH];
volume_name.pop(); volume_name.pop();
unsafe { unsafe {
@ -289,7 +289,7 @@ impl MountInfo {
} else { } else {
None None
}; };
let mut mn_info = MountInfo { let mut mn_info = Self {
dev_id: volume_name, dev_id: volume_name,
dev_name, dev_name,
fs_type: fs_type.unwrap_or_else(|| "".to_string()), fs_type: fs_type.unwrap_or_else(|| "".to_string()),
@ -319,7 +319,7 @@ use std::ffi::CStr;
))] ))]
impl From<StatFs> for MountInfo { impl From<StatFs> for MountInfo {
fn from(statfs: StatFs) -> Self { fn from(statfs: StatFs) -> Self {
let mut info = MountInfo { let mut info = Self {
dev_id: "".to_string(), dev_id: "".to_string(),
dev_name: unsafe { dev_name: unsafe {
// spell-checker:disable-next-line // spell-checker:disable-next-line
@ -553,7 +553,7 @@ impl FsUsage {
} }
let bytes_per_cluster = sectors_per_cluster as u64 * bytes_per_sector as u64; let bytes_per_cluster = sectors_per_cluster as u64 * bytes_per_sector as u64;
FsUsage { Self {
// f_bsize File system block size. // f_bsize File system block size.
blocksize: bytes_per_cluster as u64, blocksize: bytes_per_cluster as u64,
// f_blocks - Total number of blocks on the file system, in units of f_frsize. // f_blocks - Total number of blocks on the file system, in units of f_frsize.

View file

@ -27,10 +27,10 @@ pub trait FromWide {
fn from_wide_null(wide: &[u16]) -> Self; fn from_wide_null(wide: &[u16]) -> Self;
} }
impl FromWide for String { impl FromWide for String {
fn from_wide(wide: &[u16]) -> String { fn from_wide(wide: &[u16]) -> Self {
OsString::from_wide(wide).to_string_lossy().into_owned() OsString::from_wide(wide).to_string_lossy().into_owned()
} }
fn from_wide_null(wide: &[u16]) -> String { fn from_wide_null(wide: &[u16]) -> Self {
let len = wide.iter().take_while(|&&c| c != 0).count(); let len = wide.iter().take_while(|&&c| c != 0).count();
OsString::from_wide(&wide[..len]) OsString::from_wide(&wide[..len])
.to_string_lossy() .to_string_lossy()

View file

@ -179,15 +179,15 @@ fn test_du_hard_link() {
#[cfg(target_vendor = "apple")] #[cfg(target_vendor = "apple")]
fn _du_hard_link(s: &str) { fn _du_hard_link(s: &str) {
assert_eq!(s, "12\tsubdir/links\n") assert_eq!(s, "12\tsubdir/links\n");
} }
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
fn _du_hard_link(s: &str) { fn _du_hard_link(s: &str) {
assert_eq!(s, "8\tsubdir/links\n") assert_eq!(s, "8\tsubdir/links\n");
} }
#[cfg(target_os = "freebsd")] #[cfg(target_os = "freebsd")]
fn _du_hard_link(s: &str) { fn _du_hard_link(s: &str) {
assert_eq!(s, "16\tsubdir/links\n") assert_eq!(s, "16\tsubdir/links\n");
} }
#[cfg(all( #[cfg(all(
not(target_vendor = "apple"), not(target_vendor = "apple"),

View file

@ -219,7 +219,7 @@ fn test_change_directory() {
.args(&pwd) .args(&pwd)
.succeeds() .succeeds()
.stdout_move_str(); .stdout_move_str();
assert_eq!(out.trim(), temporary_path.as_os_str()) assert_eq!(out.trim(), temporary_path.as_os_str());
} }
#[test] #[test]

View file

@ -1,6 +1,53 @@
use crate::common::util::*; use crate::common::util::*;
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "netbsd"))]
use std::fs::OpenOptions;
#[test] #[test]
fn test_exit_code() { fn test_exit_code() {
new_ucmd!().fails(); new_ucmd!().fails();
} }
#[test]
fn test_version() {
new_ucmd!()
.args(&["--version"])
.fails()
.stdout_contains("false");
}
#[test]
fn test_help() {
new_ucmd!()
.args(&["--help"])
.fails()
.stdout_contains("false");
}
#[test]
fn test_short_options() {
for option in ["-h", "-V"] {
new_ucmd!().arg(option).fails().stdout_is("");
}
}
#[test]
fn test_conflict() {
new_ucmd!()
.args(&["--help", "--version"])
.fails()
.stdout_is("");
}
#[test]
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "netbsd"))]
fn test_full() {
for option in ["--version", "--help"] {
let dev_full = OpenOptions::new().write(true).open("/dev/full").unwrap();
new_ucmd!()
.arg(option)
.set_stdout(dev_full)
.fails()
.stderr_contains("No space left on device");
}
}

View file

@ -1,6 +1,53 @@
use crate::common::util::*; use crate::common::util::*;
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "netbsd"))]
use std::fs::OpenOptions;
#[test] #[test]
fn test_exit_code() { fn test_exit_code() {
new_ucmd!().succeeds(); new_ucmd!().succeeds();
} }
#[test]
fn test_version() {
new_ucmd!()
.args(&["--version"])
.succeeds()
.stdout_contains("true");
}
#[test]
fn test_help() {
new_ucmd!()
.args(&["--help"])
.succeeds()
.stdout_contains("true");
}
#[test]
fn test_short_options() {
for option in ["-h", "-V"] {
new_ucmd!().arg(option).succeeds().stdout_is("");
}
}
#[test]
fn test_conflict() {
new_ucmd!()
.args(&["--help", "--version"])
.succeeds()
.stdout_is("");
}
#[test]
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "netbsd"))]
fn test_full() {
for option in ["--version", "--help"] {
let dev_full = OpenOptions::new().write(true).open("/dev/full").unwrap();
new_ucmd!()
.arg(option)
.set_stdout(dev_full)
.fails()
.stderr_contains("No space left on device");
}
}

View file

@ -250,13 +250,26 @@ fn test_size_and_reference() {
#[test] #[test]
fn test_error_filename_only() { fn test_error_filename_only() {
// truncate: you must specify either '--size' or '--reference' // truncate: you must specify either '--size' or '--reference'
new_ucmd!().args(&["file"]).fails().stderr_contains( new_ucmd!()
.args(&["file"])
.fails()
.code_is(1)
.stderr_contains(
"error: The following required arguments were not provided: "error: The following required arguments were not provided:
--reference <RFILE> --reference <RFILE>
--size <SIZE>", --size <SIZE>",
); );
} }
#[test]
fn test_invalid_option() {
// truncate: cli parsing error returns 1
new_ucmd!()
.args(&["--this-arg-does-not-exist"])
.fails()
.code_is(1);
}
#[test] #[test]
fn test_invalid_numbers() { fn test_invalid_numbers() {
new_ucmd!() new_ucmd!()