From 97d14893a11dd4e19488398cceb8fd8ae1948b46 Mon Sep 17 00:00:00 2001 From: Michael Debertol Date: Sun, 27 Jun 2021 18:23:10 +0200 Subject: [PATCH 01/25] [: install test as [ as well --- GNUmakefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/GNUmakefile b/GNUmakefile index 89a4dca80..bb82925ec 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -1,4 +1,4 @@ -# spell-checker:ignore (misc) testsuite runtest (targets) busytest distclean manpages pkgs ; (vars/env) BINDIR BUILDDIR CARGOFLAGS DESTDIR DOCSDIR INSTALLDIR INSTALLEES MANDIR MULTICALL +# spell-checker:ignore (misc) testsuite runtest findstring (targets) busytest distclean manpages pkgs ; (vars/env) BINDIR BUILDDIR CARGOFLAGS DESTDIR DOCSDIR INSTALLDIR INSTALLEES MANDIR MULTICALL # Config options PROFILE ?= debug @@ -307,10 +307,12 @@ ifeq (${MULTICALL}, y) $(INSTALL) $(BUILDDIR)/coreutils $(INSTALLDIR_BIN)/$(PROG_PREFIX)coreutils cd $(INSTALLDIR_BIN) && $(foreach prog, $(filter-out coreutils, $(INSTALLEES)), \ ln -fs $(PROG_PREFIX)coreutils $(PROG_PREFIX)$(prog) &&) : + $(if $(findstring test,$(INSTALLEES)), ln -fs $(PROG_PREFIX)coreutils $(PROG_PREFIX)[) cat $(DOCSDIR)/_build/man/coreutils.1 | gzip > $(INSTALLDIR_MAN)/$(PROG_PREFIX)coreutils.1.gz else $(foreach prog, $(INSTALLEES), \ $(INSTALL) $(BUILDDIR)/$(prog) $(INSTALLDIR_BIN)/$(PROG_PREFIX)$(prog);) + $(if $(findstring test,$(INSTALLEES)), $(INSTALL) $(BUILDDIR)/test $(INSTALLDIR_BIN)/$(PROG_PREFIX)[) endif $(foreach man, $(filter $(INSTALLEES), $(basename $(notdir $(wildcard $(DOCSDIR)/_build/man/*)))), \ cat $(DOCSDIR)/_build/man/$(man).1 | gzip > $(INSTALLDIR_MAN)/$(PROG_PREFIX)$(man).1.gz &&) : @@ -326,6 +328,7 @@ ifeq (${MULTICALL}, y) endif rm -f $(addprefix $(INSTALLDIR_MAN)/,$(PROG_PREFIX)coreutils.1.gz) rm -f $(addprefix $(INSTALLDIR_BIN)/$(PROG_PREFIX),$(PROGS)) + rm -f $(INSTALLDIR_BIN)/$(PROG_PREFIX)[ rm -f $(addprefix $(DESTDIR)$(PREFIX)/share/zsh/site-functions/_$(PROG_PREFIX),$(PROGS)) rm -f $(addprefix $(DESTDIR)$(PREFIX)/share/bash-completion/completions/$(PROG_PREFIX),$(PROGS)) rm -f $(addprefix $(DESTDIR)$(PREFIX)/share/fish/vendor_completions.d/$(PROG_PREFIX),$(addsuffix .fish,$(PROGS))) From cd83aed89c0e1108212cd83373b634bad9f615c2 Mon Sep 17 00:00:00 2001 From: Michael Debertol Date: Tue, 29 Jun 2021 00:13:04 +0200 Subject: [PATCH 02/25] test: go into '[' mode when executable ends with [ This makes [ work even when installed with a custom prefix, e.g. as uu-[. --- src/uu/test/src/test.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uu/test/src/test.rs b/src/uu/test/src/test.rs index dba840d3c..df5f1fd3e 100644 --- a/src/uu/test/src/test.rs +++ b/src/uu/test/src/test.rs @@ -31,7 +31,7 @@ pub fn uumain(mut args: impl uucore::Args) -> i32 { let mut args: Vec<_> = args.collect(); // If invoked via name '[', matching ']' must be in the last arg - if binary_name == "[" { + if binary_name.ends_with('[') { let last = args.pop(); if last != Some(OsString::from("]")) { eprintln!("[: missing ']'"); From 330db2eb3ecf72355d8354f909c36015de8da90a Mon Sep 17 00:00:00 2001 From: 353fc443 <353fc443@pm.me> Date: Fri, 2 Jul 2021 08:19:33 +0000 Subject: [PATCH 03/25] Added UResult for hostname --- src/uu/hostname/src/hostname.rs | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/uu/hostname/src/hostname.rs b/src/uu/hostname/src/hostname.rs index fe477d7b5..69602fc0a 100644 --- a/src/uu/hostname/src/hostname.rs +++ b/src/uu/hostname/src/hostname.rs @@ -14,6 +14,7 @@ use clap::{crate_version, App, Arg, ArgMatches}; use std::collections::hash_set::HashSet; use std::net::ToSocketAddrs; use std::str; +use uucore::error::{UResult, USimpleError}; #[cfg(windows)] use winapi::shared::minwindef::MAKEWORD; @@ -28,15 +29,15 @@ static OPT_FQDN: &str = "fqdn"; static OPT_SHORT: &str = "short"; static OPT_HOST: &str = "host"; -pub fn uumain(args: impl uucore::Args) -> i32 { +#[uucore_procs::gen_uumain] +pub fn uumain(args: impl uucore::Args) -> UResult<()> { #![allow(clippy::let_and_return)] #[cfg(windows)] unsafe { #[allow(deprecated)] let mut data = std::mem::uninitialized(); if WSAStartup(MAKEWORD(2, 2), &mut data as *mut _) != 0 { - eprintln!("Failed to start Winsock 2.2"); - return 1; + return Err(USimpleError::new(1, format!("Failed to start Winsock 2.2"))); } } let result = execute(args); @@ -50,7 +51,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 { fn get_usage() -> String { format!("{0} [OPTION]... [HOSTNAME]", executable!()) } -fn execute(args: impl uucore::Args) -> i32 { +fn execute(args: impl uucore::Args) -> UResult<()> { let usage = get_usage(); let matches = uu_app().usage(&usage[..]).get_matches_from(args); @@ -58,10 +59,9 @@ fn execute(args: impl uucore::Args) -> i32 { None => display_hostname(&matches), Some(host) => { if let Err(err) = hostname::set(host) { - show_error!("{}", err); - 1 + return Err(USimpleError::new(1, format!("{}", err))); } else { - 0 + Ok(()) } } } @@ -97,7 +97,7 @@ pub fn uu_app() -> App<'static, 'static> { .arg(Arg::with_name(OPT_HOST)) } -fn display_hostname(matches: &ArgMatches) -> i32 { +fn display_hostname(matches: &ArgMatches) -> UResult<()> { let hostname = hostname::get().unwrap().into_string().unwrap(); if matches.is_present(OPT_IP_ADDRESS) { @@ -127,12 +127,10 @@ fn display_hostname(matches: &ArgMatches) -> i32 { println!("{}", &output[0..len - 1]); } - 0 + Ok(()) } Err(f) => { - show_error!("{}", f); - - 1 + return Err(USimpleError::new(1, format!("{}", f))); } } } else { @@ -144,12 +142,12 @@ fn display_hostname(matches: &ArgMatches) -> i32 { } else { println!("{}", &hostname[ci.0 + 1..]); } - return 0; + return Ok(()); } } println!("{}", hostname); - 0 + Ok(()) } } From f66f10c4ede2a65a33ab7c4513377adb1ef69299 Mon Sep 17 00:00:00 2001 From: 353fc443 <353fc443@pm.me> Date: Fri, 2 Jul 2021 12:03:14 +0000 Subject: [PATCH 04/25] Added UResult for hostid --- src/uu/hostid/src/hostid.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/uu/hostid/src/hostid.rs b/src/uu/hostid/src/hostid.rs index e9fc08379..b0f68968d 100644 --- a/src/uu/hostid/src/hostid.rs +++ b/src/uu/hostid/src/hostid.rs @@ -12,6 +12,7 @@ extern crate uucore; use clap::{crate_version, App}; use libc::c_long; +use uucore::error::UResult; static SYNTAX: &str = "[options]"; @@ -20,10 +21,11 @@ extern "C" { pub fn gethostid() -> c_long; } -pub fn uumain(args: impl uucore::Args) -> i32 { +#[uucore_procs::gen_uumain] +pub fn uumain(args: impl uucore::Args) -> UResult<()> { uu_app().get_matches_from(args); hostid(); - 0 + Ok(()) } pub fn uu_app() -> App<'static, 'static> { From 23f5f55560a493b2de6287451e07ede8ba5aa367 Mon Sep 17 00:00:00 2001 From: 353fc443 <353fc443@pm.me> Date: Fri, 2 Jul 2021 12:14:24 +0000 Subject: [PATCH 05/25] Added UResult for dirname --- src/uu/dirname/src/dirname.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/uu/dirname/src/dirname.rs b/src/uu/dirname/src/dirname.rs index 356f2e6b1..797e51808 100644 --- a/src/uu/dirname/src/dirname.rs +++ b/src/uu/dirname/src/dirname.rs @@ -10,6 +10,7 @@ extern crate uucore; use clap::{crate_version, App, Arg}; use std::path::Path; +use uucore::error::{UResult, USimpleError}; use uucore::InvalidEncodingHandling; static ABOUT: &str = "strip last component from file name"; @@ -30,7 +31,8 @@ fn get_long_usage() -> String { ) } -pub fn uumain(args: impl uucore::Args) -> i32 { +#[uucore_procs::gen_uumain] +pub fn uumain(args: impl uucore::Args) -> UResult<()> { let args = args .collect_str(InvalidEncodingHandling::ConvertLossy) .accept_any(); @@ -77,11 +79,10 @@ pub fn uumain(args: impl uucore::Args) -> i32 { print!("{}", separator); } } else { - show_usage_error!("missing operand"); - return 1; + return Err(USimpleError::new(1, format!("missing operand"))); } - 0 + Ok(()) } pub fn uu_app() -> App<'static, 'static> { From 38c08809891f6d7bea2e0df3e9e08073825275f3 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Sun, 4 Jul 2021 12:03:36 +0200 Subject: [PATCH 06/25] fix the clippy warning --- src/uu/dirname/src/dirname.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uu/dirname/src/dirname.rs b/src/uu/dirname/src/dirname.rs index 797e51808..d84bd4b80 100644 --- a/src/uu/dirname/src/dirname.rs +++ b/src/uu/dirname/src/dirname.rs @@ -79,7 +79,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { print!("{}", separator); } } else { - return Err(USimpleError::new(1, format!("missing operand"))); + return Err(UUsageError::new(1, "missing operand".to_string())); } Ok(()) From d0805605e0110211f7a849101fd0669950c5c356 Mon Sep 17 00:00:00 2001 From: 353fc443 <85840256+353fc443@users.noreply.github.com> Date: Sun, 4 Jul 2021 16:09:55 +0530 Subject: [PATCH 07/25] imported UUsageError --- src/uu/dirname/src/dirname.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uu/dirname/src/dirname.rs b/src/uu/dirname/src/dirname.rs index d84bd4b80..63ee57272 100644 --- a/src/uu/dirname/src/dirname.rs +++ b/src/uu/dirname/src/dirname.rs @@ -10,7 +10,7 @@ extern crate uucore; use clap::{crate_version, App, Arg}; use std::path::Path; -use uucore::error::{UResult, USimpleError}; +use uucore::error::{UResult, UUsageError}; use uucore::InvalidEncodingHandling; static ABOUT: &str = "strip last component from file name"; From a9ba4c6d9f5658d4fe0e7ede56b4e41305de9203 Mon Sep 17 00:00:00 2001 From: Anup Mahindre Date: Sun, 4 Jul 2021 17:13:22 +0530 Subject: [PATCH 08/25] du: Use UResult --- src/uu/du/src/du.rs | 131 ++++++++++++++++++++++++++++---------------- 1 file changed, 83 insertions(+), 48 deletions(-) diff --git a/src/uu/du/src/du.rs b/src/uu/du/src/du.rs index 05167853c..437668947 100644 --- a/src/uu/du/src/du.rs +++ b/src/uu/du/src/du.rs @@ -31,6 +31,8 @@ use std::path::Path; use std::path::PathBuf; use std::str::FromStr; use std::time::{Duration, UNIX_EPOCH}; +use std::{error::Error, fmt::Display}; +use uucore::error::{UCustomError, UResult}; use uucore::parse_size::{parse_size, ParseSizeError}; use uucore::InvalidEncodingHandling; #[cfg(windows)] @@ -399,8 +401,61 @@ fn get_usage() -> String { ) } +#[derive(Debug)] +enum DuError { + InvalidMaxDepthArg(String), + SummarizeDepthConflict(String), + InvalidTimeStyleArg(String), + InvalidTimeArg(String), +} + +impl Display for DuError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + DuError::InvalidMaxDepthArg(s) => write!(f, "invalid maximum depth '{}'", s), + DuError::SummarizeDepthConflict(s) => { + write!(f, "summarizing conflicts with --max-depth={}", s) + } + DuError::InvalidTimeStyleArg(s) => { + write!( + f, + "invalid argument '{}' for 'time style' +Valid arguments are: +- 'full-iso' +- 'long-iso' +- 'iso' +Try '{} --help' for more information.", + s, NAME + ) + } + DuError::InvalidTimeArg(s) => { + write!( + f, + "Invalid argument '{}' for --time. +'birth' and 'creation' arguments are not supported on this platform.", + s + ) + } + } + } +} + +impl Error for DuError {} + +impl UCustomError for DuError { + fn code(&self) -> i32 { + match self { + Self::InvalidMaxDepthArg(_) => 1, + Self::SummarizeDepthConflict(_) => 1, + Self::InvalidTimeStyleArg(_) => 1, + Self::InvalidTimeArg(_) => 1, + } + } +} + +#[uucore_procs::gen_uumain] #[allow(clippy::cognitive_complexity)] -pub fn uumain(args: impl uucore::Args) -> i32 { +pub fn uumain(args: impl uucore::Args) -> UResult<()> { let args = args .collect_str(InvalidEncodingHandling::Ignore) .accept_any(); @@ -411,19 +466,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 { let summarize = matches.is_present(options::SUMMARIZE); - let max_depth_str = matches.value_of(options::MAX_DEPTH); - let max_depth = max_depth_str.as_ref().and_then(|s| s.parse::().ok()); - match (max_depth_str, max_depth) { - (Some(s), _) if summarize => { - show_error!("summarizing conflicts with --max-depth={}", s); - return 1; - } - (Some(s), None) => { - show_error!("invalid maximum depth '{}'", s); - return 1; - } - (Some(_), Some(_)) | (None, _) => { /* valid */ } - } + let max_depth = parse_depth(matches.value_of(options::MAX_DEPTH), summarize)?; let options = Options { all: matches.is_present(options::ALL), @@ -480,27 +523,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 { } }; - let time_format_str = match matches.value_of("time-style") { - Some(s) => match s { - "full-iso" => "%Y-%m-%d %H:%M:%S.%f %z", - "long-iso" => "%Y-%m-%d %H:%M", - "iso" => "%Y-%m-%d", - _ => { - show_error!( - "invalid argument '{}' for 'time style' -Valid arguments are: -- 'full-iso' -- 'long-iso' -- 'iso' -Try '{} --help' for more information.", - s, - NAME - ); - return 1; - } - }, - None => "%Y-%m-%d %H:%M", - }; + let time_format_str = parse_time_style(matches.value_of("time-style"))?; let line_separator = if matches.is_present(options::NULL) { "\0" @@ -534,18 +557,9 @@ Try '{} --help' for more information.", Some(s) => match s { "ctime" | "status" => stat.modified, "access" | "atime" | "use" => stat.accessed, - "birth" | "creation" => { - if let Some(time) = stat.created { - time - } else { - show_error!( - "Invalid argument '{}' for --time. -'birth' and 'creation' arguments are not supported on this platform.", - s - ); - return 1; - } - } + "birth" | "creation" => stat + .created + .ok_or_else(|| DuError::InvalidTimeArg(s.into()))?, // below should never happen as clap already restricts the values. _ => unreachable!("Invalid field for --time"), }, @@ -590,7 +604,28 @@ Try '{} --help' for more information.", print!("{}", line_separator); } - 0 + Ok(()) +} + +fn parse_time_style(s: Option<&str>) -> UResult<&str> { + match s { + Some(s) => match s { + "full-iso" => Ok("%Y-%m-%d %H:%M:%S.%f %z"), + "long-iso" => Ok("%Y-%m-%d %H:%M"), + "iso" => Ok("%Y-%m-%d"), + _ => Err(DuError::InvalidTimeStyleArg(s.into()).into()), + }, + None => Ok("%Y-%m-%d %H:%M"), + } +} + +fn parse_depth(max_depth_str: Option<&str>, summarize: bool) -> UResult> { + let max_depth = max_depth_str.as_ref().and_then(|s| s.parse::().ok()); + match (max_depth_str, max_depth) { + (Some(s), _) if summarize => Err(DuError::SummarizeDepthConflict(s.into()).into()), + (Some(s), None) => Err(DuError::InvalidMaxDepthArg(s.into()).into()), + (Some(_), Some(_)) | (None, _) => Ok(max_depth), + } } pub fn uu_app() -> App<'static, 'static> { From c74b77aec895bb8cd91c4e1ea83cff291680b9e6 Mon Sep 17 00:00:00 2001 From: Dave Hodder Date: Mon, 5 Jul 2021 22:42:42 +0100 Subject: [PATCH 09/25] uname: don't report OS as "GNU/Linux" without GNU The `uname` `-o` switch reports the operating system used. If the GNU C standard library (glibc) is not in use, for example if musl is being used instead, report "Linux" instead of "GNU/Linux". --- src/uu/uname/src/uname.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/uu/uname/src/uname.rs b/src/uu/uname/src/uname.rs index dda859722..26b4ddd2a 100644 --- a/src/uu/uname/src/uname.rs +++ b/src/uu/uname/src/uname.rs @@ -30,8 +30,10 @@ pub mod options { pub static OS: &str = "operating-system"; } -#[cfg(target_os = "linux")] +#[cfg(all(target_os = "linux", any(target_env = "gnu", target_env = "")))] const HOST_OS: &str = "GNU/Linux"; +#[cfg(all(target_os = "linux", not(any(target_env = "gnu", target_env = ""))))] +const HOST_OS: &str = "Linux"; #[cfg(target_os = "windows")] const HOST_OS: &str = "Windows NT"; #[cfg(target_os = "freebsd")] From 16a5faf8863704d866182c256c78d35b4aef9c58 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Tue, 6 Jul 2021 11:49:02 +0200 Subject: [PATCH 10/25] Silent buggy clippy warnings --- src/uu/dirname/src/dirname.rs | 3 +++ src/uu/hostid/src/hostid.rs | 3 +++ src/uu/hostname/src/hostname.rs | 3 +++ 3 files changed, 9 insertions(+) diff --git a/src/uu/dirname/src/dirname.rs b/src/uu/dirname/src/dirname.rs index 63ee57272..8d85dc85e 100644 --- a/src/uu/dirname/src/dirname.rs +++ b/src/uu/dirname/src/dirname.rs @@ -5,6 +5,9 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. +// Clippy bug: https://github.com/rust-lang/rust-clippy/issues/7422 +#![allow(clippy::nonstandard_macro_braces)] + #[macro_use] extern crate uucore; diff --git a/src/uu/hostid/src/hostid.rs b/src/uu/hostid/src/hostid.rs index b0f68968d..180c4d2e5 100644 --- a/src/uu/hostid/src/hostid.rs +++ b/src/uu/hostid/src/hostid.rs @@ -7,6 +7,9 @@ // spell-checker:ignore (ToDO) gethostid +// Clippy bug: https://github.com/rust-lang/rust-clippy/issues/7422 +#![allow(clippy::nonstandard_macro_braces)] + #[macro_use] extern crate uucore; diff --git a/src/uu/hostname/src/hostname.rs b/src/uu/hostname/src/hostname.rs index 69602fc0a..5f05fa05c 100644 --- a/src/uu/hostname/src/hostname.rs +++ b/src/uu/hostname/src/hostname.rs @@ -7,6 +7,9 @@ // spell-checker:ignore (ToDO) MAKEWORD addrs hashset +// Clippy bug: https://github.com/rust-lang/rust-clippy/issues/7422 +#![allow(clippy::nonstandard_macro_braces)] + #[macro_use] extern crate uucore; From d5b2320a59b338f1ac42c27c191ec659a63f14fb Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Tue, 6 Jul 2021 12:30:12 +0200 Subject: [PATCH 11/25] Fix clippy warning Useless use of format --- src/uu/hostname/src/hostname.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/uu/hostname/src/hostname.rs b/src/uu/hostname/src/hostname.rs index 5f05fa05c..14f8b9df2 100644 --- a/src/uu/hostname/src/hostname.rs +++ b/src/uu/hostname/src/hostname.rs @@ -17,6 +17,8 @@ use clap::{crate_version, App, Arg, ArgMatches}; use std::collections::hash_set::HashSet; use std::net::ToSocketAddrs; use std::str; +#[cfg(windows)] +use uucore::error::UUsageError; use uucore::error::{UResult, USimpleError}; #[cfg(windows)] @@ -40,7 +42,10 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { #[allow(deprecated)] let mut data = std::mem::uninitialized(); if WSAStartup(MAKEWORD(2, 2), &mut data as *mut _) != 0 { - return Err(USimpleError::new(1, format!("Failed to start Winsock 2.2"))); + return Err(UUsageError::new( + 1, + "Failed to start Winsock 2.2".to_string(), + )); } } let result = execute(args); From bc0727cc4d1748bdf19b67ecfe56b8e5094c7dd9 Mon Sep 17 00:00:00 2001 From: Michael Debertol Date: Tue, 29 Jun 2021 20:49:02 +0200 Subject: [PATCH 12/25] [: add support for --help and --version I copied the help text verbatim from GNU, I hope that's ok. --- src/uu/test/src/test.rs | 88 +++++++++++++++++++++++++++++++++++++- tests/by-util/test_test.rs | 18 ++++++++ 2 files changed, 104 insertions(+), 2 deletions(-) diff --git a/src/uu/test/src/test.rs b/src/uu/test/src/test.rs index df5f1fd3e..bed1472e2 100644 --- a/src/uu/test/src/test.rs +++ b/src/uu/test/src/test.rs @@ -10,12 +10,82 @@ mod parser; -use clap::{App, AppSettings}; +use clap::{crate_version, App, AppSettings}; use parser::{parse, Symbol}; use std::ffi::{OsStr, OsString}; use std::path::Path; use uucore::executable; +const USAGE: &str = "test EXPRESSION +or: test +or: [ EXPRESSION ] +or: [ ] +or: [ OPTION"; + +// We use after_help so that this comes after the usage string (it would come before if we used about) +const AFTER_HELP: &str = " +Exit with the status determined by EXPRESSION. + +An omitted EXPRESSION defaults to false. Otherwise, +EXPRESSION is true or false and sets exit status. It is one of: + + ( EXPRESSION ) EXPRESSION is true + ! EXPRESSION EXPRESSION is false + EXPRESSION1 -a EXPRESSION2 both EXPRESSION1 and EXPRESSION2 are true + EXPRESSION1 -o EXPRESSION2 either EXPRESSION1 or EXPRESSION2 is true + + -n STRING the length of STRING is nonzero + STRING equivalent to -n STRING + -z STRING the length of STRING is zero + STRING1 = STRING2 the strings are equal + STRING1 != STRING2 the strings are not equal + + INTEGER1 -eq INTEGER2 INTEGER1 is equal to INTEGER2 + INTEGER1 -ge INTEGER2 INTEGER1 is greater than or equal to INTEGER2 + INTEGER1 -gt INTEGER2 INTEGER1 is greater than INTEGER2 + INTEGER1 -le INTEGER2 INTEGER1 is less than or equal to INTEGER2 + INTEGER1 -lt INTEGER2 INTEGER1 is less than INTEGER2 + INTEGER1 -ne INTEGER2 INTEGER1 is not equal to INTEGER2 + + FILE1 -ef FILE2 FILE1 and FILE2 have the same device and inode numbers + FILE1 -nt FILE2 FILE1 is newer (modification date) than FILE2 + FILE1 -ot FILE2 FILE1 is older than FILE2 + + -b FILE FILE exists and is block special + -c FILE FILE exists and is character special + -d FILE FILE exists and is a directory + -e FILE FILE exists + -f FILE FILE exists and is a regular file + -g FILE FILE exists and is set-group-ID + -G FILE FILE exists and is owned by the effective group ID + -h FILE FILE exists and is a symbolic link (same as -L) + -k FILE FILE exists and has its sticky bit set + -L FILE FILE exists and is a symbolic link (same as -h) + -N FILE FILE exists and has been modified since it was last read + -O FILE FILE exists and is owned by the effective user ID + -p FILE FILE exists and is a named pipe + -r FILE FILE exists and read permission is granted + -s FILE FILE exists and has a size greater than zero + -S FILE FILE exists and is a socket + -t FD file descriptor FD is opened on a terminal + -u FILE FILE exists and its set-user-ID bit is set + -w FILE FILE exists and write permission is granted + -x FILE FILE exists and execute (or search) permission is granted + +Except for -h and -L, all FILE-related tests dereference symbolic links. +Beware that parentheses need to be escaped (e.g., by backslashes) for shells. +INTEGER may also be -l STRING, which evaluates to the length of STRING. + +NOTE: Binary -a and -o are inherently ambiguous. Use 'test EXPR1 && test +EXPR2' or 'test EXPR1 || test EXPR2' instead. + +NOTE: [ honors the --help and --version options, but test does not. +test treats each of those as it treats any other nonempty STRING. + +NOTE: your shell may have its own version of test and/or [, which usually supersedes +the version described here. Please refer to your shell's documentation +for details about the options it supports."; + pub fn uu_app() -> App<'static, 'static> { App::new(executable!()) .setting(AppSettings::DisableHelpFlags) @@ -30,8 +100,22 @@ pub fn uumain(mut args: impl uucore::Args) -> i32 { .to_string_lossy(); let mut args: Vec<_> = args.collect(); - // If invoked via name '[', matching ']' must be in the last arg if binary_name.ends_with('[') { + // If invoked as [ we should recognize --help and --version (but not -h or -v) + if args.len() == 1 && (args[0] == "--help" || args[0] == "--version") { + // Let clap pretty-print help and version + App::new(binary_name) + .version(crate_version!()) + .usage(USAGE) + .after_help(AFTER_HELP) + // Disable printing of -h and -v as valid alternatives for --help and --version, + // since we don't recognize -h and -v as help/version flags. + .setting(AppSettings::NeedsLongHelp) + .setting(AppSettings::NeedsLongVersion) + .get_matches_from(std::iter::once(program).chain(args.into_iter())); + return 0; + } + // If invoked via name '[', matching ']' must be in the last arg let last = args.pop(); if last != Some(OsString::from("]")) { eprintln!("[: missing ']'"); diff --git a/tests/by-util/test_test.rs b/tests/by-util/test_test.rs index 1867927da..79c24651a 100644 --- a/tests/by-util/test_test.rs +++ b/tests/by-util/test_test.rs @@ -718,3 +718,21 @@ fn test_bracket_syntax_missing_right_bracket() { .status_code(2) .stderr_is("[: missing ']'"); } + +#[test] +fn test_bracket_syntax_help() { + let scenario = TestScenario::new("["); + let mut ucmd = scenario.ucmd(); + + ucmd.arg("--help").succeeds().stdout_contains("USAGE:"); +} + +#[test] +fn test_bracket_syntax_version() { + let scenario = TestScenario::new("["); + let mut ucmd = scenario.ucmd(); + + ucmd.arg("--version") + .succeeds() + .stdout_matches(&r"\[ \d+\.\d+\.\d+".parse().unwrap()); +} From 8ace291b3292f2f422cf9670ccd98be983f44bf3 Mon Sep 17 00:00:00 2001 From: Michael Debertol Date: Tue, 6 Jul 2021 13:26:28 +0200 Subject: [PATCH 13/25] sort: make -k only take one argument per flag This makes it so that `sort -k 1 file` treats `file` as the input file and not the second key. --- src/uu/sort/src/sort.rs | 1 + tests/by-util/test_sort.rs | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/src/uu/sort/src/sort.rs b/src/uu/sort/src/sort.rs index 1ba5ee0b5..55bcdb77b 100644 --- a/src/uu/sort/src/sort.rs +++ b/src/uu/sort/src/sort.rs @@ -1267,6 +1267,7 @@ pub fn uu_app() -> App<'static, 'static> { .help("sort by a key") .long_help(LONG_HELP_KEYS) .multiple(true) + .number_of_values(1) .takes_value(true), ) .arg( diff --git a/tests/by-util/test_sort.rs b/tests/by-util/test_sort.rs index 1d41ddac5..4a1cc3fa9 100644 --- a/tests/by-util/test_sort.rs +++ b/tests/by-util/test_sort.rs @@ -951,3 +951,11 @@ fn test_conflict_check_out() { ); } } + +#[test] +fn test_key_takes_one_arg() { + new_ucmd!() + .args(&["-k", "2.3", "keys_open_ended.txt"]) + .succeeds() + .stdout_is_fixture("keys_open_ended.expected"); +} From 330f797378e673835c89dc82ad30e8ea52ea7455 Mon Sep 17 00:00:00 2001 From: Dave Hodder Date: Tue, 6 Jul 2021 23:40:38 +0100 Subject: [PATCH 14/25] tests/uname: add `--operating-system` test --- tests/by-util/test_uname.rs | 62 +++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/tests/by-util/test_uname.rs b/tests/by-util/test_uname.rs index de3f42a6b..adcaa1072 100644 --- a/tests/by-util/test_uname.rs +++ b/tests/by-util/test_uname.rs @@ -1,5 +1,10 @@ use crate::common::util::*; +#[test] +fn test_uname() { + new_ucmd!().succeeds(); +} + #[test] fn test_uname_compatible() { new_ucmd!().arg("-a").succeeds(); @@ -45,3 +50,60 @@ fn test_uname_kernel() { #[cfg(not(target_os = "linux"))] ucmd.arg("-o").succeeds(); } + +#[test] +fn test_uname_operating_system() { + #[cfg(target_vendor = "apple")] + new_ucmd!() + .arg("--operating-system") + .succeeds() + .stdout_is("Darwin\n"); + #[cfg(target_os = "freebsd")] + new_ucmd!() + .arg("--operating-system") + .succeeds() + .stdout_is("FreeBSD\n"); + #[cfg(target_os = "fuchsia")] + new_ucmd!() + .arg("--operating-system") + .succeeds() + .stdout_is("Fuchsia\n"); + #[cfg(all(target_os = "linux", any(target_env = "gnu", target_env = "")))] + new_ucmd!() + .arg("--operating-system") + .succeeds() + .stdout_is("GNU/Linux\n"); + #[cfg(all(target_os = "linux", not(any(target_env = "gnu", target_env = ""))))] + new_ucmd!() + .arg("--operating-system") + .succeeds() + .stdout_is("Linux\n"); + #[cfg(target_os = "netbsd")] + new_ucmd!() + .arg("--operating-system") + .succeeds() + .stdout_is("NetBSD\n"); + #[cfg(target_os = "openbsd")] + new_ucmd!() + .arg("--operating-system") + .succeeds() + .stdout_is("OpenBSD\n"); + #[cfg(target_os = "redox")] + new_ucmd!() + .arg("--operating-system") + .succeeds() + .stdout_is("Redox\n"); + #[cfg(target_os = "windows")] + new_ucmd!() + .arg("--operating-system") + .succeeds() + .stdout_is("Windows NT\n"); +} + +#[test] +fn test_uname_help() { + new_ucmd!() + .arg("--help") + .succeeds() + .stdout_contains("system information"); +} From 7a62d8e4e7cd104edd679fe5fd9125bc18f4a639 Mon Sep 17 00:00:00 2001 From: Dave Hodder Date: Tue, 6 Jul 2021 23:42:16 +0100 Subject: [PATCH 15/25] uname: add NetBSD to operating systems list --- src/uu/uname/src/uname.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/uu/uname/src/uname.rs b/src/uu/uname/src/uname.rs index 26b4ddd2a..abd50d1b8 100644 --- a/src/uu/uname/src/uname.rs +++ b/src/uu/uname/src/uname.rs @@ -38,6 +38,8 @@ const HOST_OS: &str = "Linux"; const HOST_OS: &str = "Windows NT"; #[cfg(target_os = "freebsd")] const HOST_OS: &str = "FreeBSD"; +#[cfg(target_os = "netbsd")] +const HOST_OS: &str = "NetBSD"; #[cfg(target_os = "openbsd")] const HOST_OS: &str = "OpenBSD"; #[cfg(target_vendor = "apple")] From c447863c8da01306f39db6e28e70663b26e8996b Mon Sep 17 00:00:00 2001 From: Jan Scheer Date: Wed, 7 Jul 2021 14:30:38 +0200 Subject: [PATCH 16/25] tests/common: refactor to reduce duplicate code * move fn expected_result to common/util.rs * move fn check_coreutil_version to common/util.rs * move fn whoami to common/util.rs * move macro unwrap_or_return to common/macros.rs * add documentation * add tests --- tests/common/macros.rs | 16 ++++ tests/common/util.rs | 198 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 213 insertions(+), 1 deletion(-) diff --git a/tests/common/macros.rs b/tests/common/macros.rs index 03d2051d0..2a1c20af2 100644 --- a/tests/common/macros.rs +++ b/tests/common/macros.rs @@ -66,3 +66,19 @@ macro_rules! at_and_ucmd { (ts.fixtures.clone(), ts.ucmd()) }}; } + +/// If `common::util::expected_result` returns an error, i.e. the `util` in `$PATH` doesn't +/// include a coreutils version string or the version is too low, +/// this macro can be used to automatically skip the test and print the reason. +#[macro_export] +macro_rules! unwrap_or_return { + ( $e:expr ) => { + match $e { + Ok(x) => x, + Err(e) => { + println!("test skipped: {}", e); + return; + } + } + }; +} diff --git a/tests/common/util.rs b/tests/common/util.rs index f881cff21..79af471e3 100644 --- a/tests/common/util.rs +++ b/tests/common/util.rs @@ -1,10 +1,11 @@ -//spell-checker: ignore (linux) rlimit prlimit Rlim +//spell-checker: ignore (linux) rlimit prlimit Rlim coreutil #![allow(dead_code)] use pretty_assertions::assert_eq; #[cfg(target_os = "linux")] use rlimit::{prlimit, rlim}; +use std::borrow::Cow; use std::env; #[cfg(not(windows))] use std::ffi::CString; @@ -1036,6 +1037,179 @@ pub fn vec_of_size(n: usize) -> Vec { result } +pub fn whoami() -> String { + // Apparently some CI environments have configuration issues, e.g. with 'whoami' and 'id'. + // + // From the Logs: "Build (ubuntu-18.04, x86_64-unknown-linux-gnu, feat_os_unix, use-cross)" + // whoami: cannot find name for user ID 1001 + // id --name: cannot find name for user ID 1001 + // id --name: cannot find name for group ID 116 + // + // However, when running "id" from within "/bin/bash" it looks fine: + // id: "uid=1001(runner) gid=118(docker) groups=118(docker),4(adm),101(systemd-journal)" + // whoami: "runner" + + // Use environment variable to get current user instead of + // invoking `whoami` and fall back to user "nobody" on error. + std::env::var("USER").unwrap_or_else(|e| { + println!("{}: {}, using \"nobody\" instead", UUTILS_WARNING, e); + "nobody".to_string() + }) +} + +/// Add prefix 'g' for `util_name` if not on linux +#[cfg(unix)] +pub fn host_name_for<'a>(util_name: &'a str) -> Cow<'a, str> { + // In some environments, e.g. macOS/freebsd, the GNU coreutils are prefixed with "g" + // to not interfere with the BSD counterparts already in `$PATH`. + #[cfg(not(target_os = "linux"))] + return format!("g{}", util_name).into(); + #[cfg(target_os = "linux")] + return util_name.into(); +} + +// GNU coreutils version 8.32 is the reference version since it is the latest version and the +// GNU test suite in "coreutils/.github/workflows/GnuTests.yml" runs against it. +// However, here 8.30 was chosen because right now there's no ubuntu image for the github actions +// CICD available with a higher version than 8.30. +// GNU coreutils versions from the CICD images for comparison: +// ubuntu-2004: 8.30 (latest) +// ubuntu-1804: 8.28 +// macos-latest: 8.32 +const VERSION_MIN: &str = "8.30"; // minimum Version for the reference `coreutil` in `$PATH` + +const UUTILS_WARNING: &str = "uutils-tests-warning"; +const UUTILS_INFO: &str = "uutils-tests-info"; + +/// Run `util_name --version` and return Ok if the version is >= `version_expected`. +/// Returns an error if +/// * `util_name` cannot run +/// * the version cannot be parsed +/// * the version is too low +/// +/// This is used by `expected_result` to check if the coreutils version is >= `VERSION_MIN`. +/// It makes sense to use this manually in a test if a feature +/// is tested that was introduced after `VERSION_MIN` +/// +/// Example: +/// +/// ```no_run +/// use crate::common::util::*; +/// const VERSION_MIN_MULTIPLE_USERS: &str = "8.31"; +/// +/// #[test] +/// fn test_xyz() { +/// unwrap_or_return!(check_coreutil_version( +/// util_name!(), +/// VERSION_MIN_MULTIPLE_USERS +/// )); +/// // proceed with the test... +/// } +/// ``` +#[cfg(unix)] +pub fn check_coreutil_version( + util_name: &str, + version_expected: &str, +) -> std::result::Result { + // example: + // $ id --version | head -n 1 + // id (GNU coreutils) 8.32.162-4eda + + let util_name = &host_name_for(util_name); + log_info("run", format!("{} --version", util_name)); + let version_check = match Command::new(util_name.as_ref()) + .env("LC_ALL", "C") + .arg("--version") + .output() + { + Ok(s) => s, + Err(e) => { + return Err(format!( + "{}: '{}' {}", + UUTILS_WARNING, + util_name, + e.to_string() + )) + } + }; + std::str::from_utf8(&version_check.stdout).unwrap() + .split('\n') + .collect::>() + .get(0) + .map_or_else( + || Err(format!("{}: unexpected output format for reference coreutil: '{} --version'", UUTILS_WARNING, util_name)), + |s| { + if s.contains(&format!("(GNU coreutils) {}", version_expected)) { + Ok(format!("{}: {}", UUTILS_INFO, s.to_string())) + } else if s.contains("(GNU coreutils)") { + let version_found = s.split_whitespace().last().unwrap()[..4].parse::().unwrap_or_default(); + let version_expected = version_expected.parse::().unwrap_or_default(); + if version_found > version_expected { + Ok(format!("{}: version for the reference coreutil '{}' is higher than expected; expected: {}, found: {}", UUTILS_INFO, util_name, version_expected, version_found)) + } else { + Err(format!("{}: version for the reference coreutil '{}' does not match; expected: {}, found: {}", UUTILS_WARNING, util_name, version_expected, version_found)) } + } else { + Err(format!("{}: no coreutils version string found for reference coreutils '{} --version'", UUTILS_WARNING, util_name)) + } + }, + ) +} + +/// This runs the GNU coreutils `util_name` binary in `$PATH` in order to +/// dynamically gather reference values on the system. +/// If the `util_name` in `$PATH` doesn't include a coreutils version string, +/// or the version is too low, this returns an error and the test should be skipped. +/// +/// Example: +/// +/// ```no_run +/// use crate::common::util::*; +/// #[test] +/// fn test_xyz() { +/// let result = new_ucmd!().run(); +/// let exp_result = unwrap_or_return!(expected_result(util_name!(), &[])); +/// result +/// .stdout_is(exp_result.stdout_str()) +/// .stderr_is(exp_result.stderr_str()) +/// .code_is(exp_result.code()); +/// } +///``` +#[cfg(unix)] +pub fn expected_result(util_name: &str, args: &[&str]) -> std::result::Result { + let util_name = &host_name_for(util_name); + println!("{}", check_coreutil_version(util_name, VERSION_MIN)?); + + let scene = TestScenario::new(util_name); + let result = scene + .cmd_keepenv(util_name.as_ref()) + .env("LC_ALL", "C") + .args(args) + .run(); + + let (stdout, stderr): (String, String) = if cfg!(target_os = "linux") { + ( + result.stdout_str().to_string(), + result.stderr_str().to_string(), + ) + } else { + // `host_name_for` added prefix, strip 'g' prefix from results: + let from = util_name.to_string() + ":"; + let to = &from[1..]; + ( + result.stdout_str().replace(&from, to), + result.stderr_str().replace(&from, to), + ) + }; + + Ok(CmdResult::new( + Some(result.tmpd()), + Some(result.code()), + result.succeeded(), + stdout.as_bytes(), + stderr.as_bytes(), + )) +} + /// Sanity checks for test utils #[cfg(test)] mod tests { @@ -1272,4 +1446,26 @@ mod tests { res.normalized_newlines_stdout_is("A\r\nB\nC\n"); } + + #[test] + #[cfg(unix)] + fn test_check_coreutil_version() { + match check_coreutil_version("id", VERSION_MIN) { + Ok(s) => s.starts_with("uutils-tests-"), + Err(s) => s.starts_with("uutils-tests-warning"), + }; + std::assert_eq!( + check_coreutil_version("no test name", VERSION_MIN), + Err("uutils-tests-warning: 'no test name' \ + No such file or directory (os error 2)" + .to_string()) + ); + } + + #[test] + #[cfg(unix)] + fn test_expected_result() { + assert!(expected_result("id", &[]).is_ok()); + assert!(expected_result("no test name", &[]).is_err()); + } } From 9631d8cf2b1cfb6612c00a2995e88d23a309dcaf Mon Sep 17 00:00:00 2001 From: Jan Scheer Date: Wed, 7 Jul 2021 15:52:56 +0200 Subject: [PATCH 17/25] test_groups: refactor use expected_result from common/util.rs --- tests/by-util/test_groups.rs | 143 ++--------------------------------- 1 file changed, 7 insertions(+), 136 deletions(-) diff --git a/tests/by-util/test_groups.rs b/tests/by-util/test_groups.rs index 9bd0cd12a..9cebdf878 100644 --- a/tests/by-util/test_groups.rs +++ b/tests/by-util/test_groups.rs @@ -1,55 +1,12 @@ use crate::common::util::*; -// spell-checker:ignore (ToDO) coreutil - -// These tests run the GNU coreutils `(g)groups` binary in `$PATH` in order to gather reference values. -// If the `(g)groups` in `$PATH` doesn't include a coreutils version string, -// or the version is too low, the test is skipped. - -// The reference version is 8.32. Here 8.30 was chosen because right now there's no -// ubuntu image for github action available with a higher version than 8.30. -const VERSION_MIN: &str = "8.30"; // minimum Version for the reference `groups` in $PATH const VERSION_MIN_MULTIPLE_USERS: &str = "8.31"; // this feature was introduced in GNU's coreutils 8.31 -const UUTILS_WARNING: &str = "uutils-tests-warning"; -const UUTILS_INFO: &str = "uutils-tests-info"; - -macro_rules! unwrap_or_return { - ( $e:expr ) => { - match $e { - Ok(x) => x, - Err(e) => { - println!("{}: test skipped: {}", UUTILS_INFO, e); - return; - } - } - }; -} - -fn whoami() -> String { - // Apparently some CI environments have configuration issues, e.g. with 'whoami' and 'id'. - // - // From the Logs: "Build (ubuntu-18.04, x86_64-unknown-linux-gnu, feat_os_unix, use-cross)" - // whoami: cannot find name for user ID 1001 - // id --name: cannot find name for user ID 1001 - // id --name: cannot find name for group ID 116 - // - // However, when running "id" from within "/bin/bash" it looks fine: - // id: "uid=1001(runner) gid=118(docker) groups=118(docker),4(adm),101(systemd-journal)" - // whoami: "runner" - - // Use environment variable to get current user instead of - // invoking `whoami` and fall back to user "nobody" on error. - std::env::var("USER").unwrap_or_else(|e| { - println!("{}: {}, using \"nobody\" instead", UUTILS_WARNING, e); - "nobody".to_string() - }) -} #[test] #[cfg(unix)] fn test_groups() { let result = new_ucmd!().run(); - let exp_result = unwrap_or_return!(expected_result(&[])); + let exp_result = unwrap_or_return!(expected_result(util_name!(), &[])); result .stdout_is(exp_result.stdout_str()) @@ -63,7 +20,7 @@ fn test_groups_username() { let test_users = [&whoami()[..]]; let result = new_ucmd!().args(&test_users).run(); - let exp_result = unwrap_or_return!(expected_result(&test_users)); + let exp_result = unwrap_or_return!(expected_result(util_name!(), &test_users)); result .stdout_is(exp_result.stdout_str()) @@ -74,103 +31,17 @@ fn test_groups_username() { #[test] #[cfg(unix)] fn test_groups_username_multiple() { - // TODO: [2021-06; jhscheer] refactor this as `let util_name = host_name_for(util_name!())` when that function is added to 'tests/common' - #[cfg(target_os = "linux")] - let util_name = util_name!(); - #[cfg(all(unix, not(target_os = "linux")))] - let util_name = &format!("g{}", util_name!()); - let version_check_string = check_coreutil_version(util_name, VERSION_MIN_MULTIPLE_USERS); - if version_check_string.starts_with(UUTILS_WARNING) { - println!("{}\ntest skipped", version_check_string); - return; - } + unwrap_or_return!(check_coreutil_version( + util_name!(), + VERSION_MIN_MULTIPLE_USERS + )); let test_users = ["root", "man", "postfix", "sshd", &whoami()]; let result = new_ucmd!().args(&test_users).run(); - let exp_result = unwrap_or_return!(expected_result(&test_users)); + let exp_result = unwrap_or_return!(expected_result(util_name!(), &test_users)); result .stdout_is(exp_result.stdout_str()) .stderr_is(exp_result.stderr_str()) .code_is(exp_result.code()); } - -fn check_coreutil_version(util_name: &str, version_expected: &str) -> String { - // example: - // $ id --version | head -n 1 - // id (GNU coreutils) 8.32.162-4eda - let scene = TestScenario::new(util_name); - let version_check = scene - .cmd_keepenv(&util_name) - .env("LC_ALL", "C") - .arg("--version") - .run(); - version_check - .stdout_str() - .split('\n') - .collect::>() - .get(0) - .map_or_else( - || format!("{}: unexpected output format for reference coreutil: '{} --version'", UUTILS_WARNING, util_name), - |s| { - if s.contains(&format!("(GNU coreutils) {}", version_expected)) { - s.to_string() - } else if s.contains("(GNU coreutils)") { - let version_found = s.split_whitespace().last().unwrap()[..4].parse::().unwrap_or_default(); - let version_expected = version_expected.parse::().unwrap_or_default(); - if version_found > version_expected { - format!("{}: version for the reference coreutil '{}' is higher than expected; expected: {}, found: {}", UUTILS_INFO, util_name, version_expected, version_found) - } else { - format!("{}: version for the reference coreutil '{}' does not match; expected: {}, found: {}", UUTILS_WARNING, util_name, version_expected, version_found) } - } else { - format!("{}: no coreutils version string found for reference coreutils '{} --version'", UUTILS_WARNING, util_name) - } - }, - ) -} - -#[allow(clippy::needless_borrow)] -#[cfg(unix)] -fn expected_result(args: &[&str]) -> Result { - // TODO: [2021-06; jhscheer] refactor this as `let util_name = host_name_for(util_name!())` when that function is added to 'tests/common' - #[cfg(target_os = "linux")] - let util_name = util_name!(); - #[cfg(all(unix, not(target_os = "linux")))] - let util_name = &format!("g{}", util_name!()); - - let version_check_string = check_coreutil_version(util_name, VERSION_MIN); - if version_check_string.starts_with(UUTILS_WARNING) { - return Err(version_check_string); - } - println!("{}", version_check_string); - - let scene = TestScenario::new(util_name); - let result = scene - .cmd_keepenv(util_name) - .env("LC_ALL", "C") - .args(args) - .run(); - - let (stdout, stderr): (String, String) = if cfg!(target_os = "linux") { - ( - result.stdout_str().to_string(), - result.stderr_str().to_string(), - ) - } else { - // strip 'g' prefix from results: - let from = util_name.to_string() + ":"; - let to = &from[1..]; - ( - result.stdout_str().replace(&from, to), - result.stderr_str().replace(&from, to), - ) - }; - - Ok(CmdResult::new( - Some(result.tmpd()), - Some(result.code()), - result.succeeded(), - stdout.as_bytes(), - stderr.as_bytes(), - )) -} From c2bd7ae9b1be95ec4ae4197a37790eb58093eeb1 Mon Sep 17 00:00:00 2001 From: Jan Scheer Date: Wed, 7 Jul 2021 15:53:26 +0200 Subject: [PATCH 18/25] test_id: refactor use expected_result from common/util.rs --- tests/by-util/test_id.rs | 198 +++++++-------------------------------- 1 file changed, 34 insertions(+), 164 deletions(-) diff --git a/tests/by-util/test_id.rs b/tests/by-util/test_id.rs index bacf57037..6c6f168fe 100644 --- a/tests/by-util/test_id.rs +++ b/tests/by-util/test_id.rs @@ -2,54 +2,13 @@ use crate::common::util::*; // spell-checker:ignore (ToDO) coreutil -// These tests run the GNU coreutils `(g)id` binary in `$PATH` in order to gather reference values. -// If the `(g)id` in `$PATH` doesn't include a coreutils version string, -// or the version is too low, the test is skipped. - -// The reference version is 8.32. Here 8.30 was chosen because right now there's no -// ubuntu image for github action available with a higher version than 8.30. -const VERSION_MIN: &str = "8.30"; // minimum Version for the reference `id` in $PATH const VERSION_MIN_MULTIPLE_USERS: &str = "8.31"; // this feature was introduced in GNU's coreutils 8.31 -const UUTILS_WARNING: &str = "uutils-tests-warning"; -const UUTILS_INFO: &str = "uutils-tests-info"; - -macro_rules! unwrap_or_return { - ( $e:expr ) => { - match $e { - Ok(x) => x, - Err(e) => { - println!("{}: test skipped: {}", UUTILS_INFO, e); - return; - } - } - }; -} - -fn whoami() -> String { - // Apparently some CI environments have configuration issues, e.g. with 'whoami' and 'id'. - // - // From the Logs: "Build (ubuntu-18.04, x86_64-unknown-linux-gnu, feat_os_unix, use-cross)" - // whoami: cannot find name for user ID 1001 - // id --name: cannot find name for user ID 1001 - // id --name: cannot find name for group ID 116 - // - // However, when running "id" from within "/bin/bash" it looks fine: - // id: "uid=1001(runner) gid=118(docker) groups=118(docker),4(adm),101(systemd-journal)" - // whoami: "runner" - - // Use environment variable to get current user instead of - // invoking `whoami` and fall back to user "nobody" on error. - std::env::var("USER").unwrap_or_else(|e| { - println!("{}: {}, using \"nobody\" instead", UUTILS_WARNING, e); - "nobody".to_string() - }) -} #[test] #[cfg(unix)] fn test_id_no_specified_user() { let result = new_ucmd!().run(); - let exp_result = unwrap_or_return!(expected_result(&[])); + let exp_result = unwrap_or_return!(expected_result(util_name!(), &[])); let mut _exp_stdout = exp_result.stdout_str().to_string(); #[cfg(target_os = "linux")] @@ -72,7 +31,7 @@ fn test_id_single_user() { let test_users = [&whoami()[..]]; let scene = TestScenario::new(util_name!()); - let mut exp_result = unwrap_or_return!(expected_result(&test_users)); + let mut exp_result = unwrap_or_return!(expected_result(util_name!(), &test_users)); scene .ucmd() .args(&test_users) @@ -85,7 +44,7 @@ fn test_id_single_user() { for &opt in &["--user", "--group", "--groups"] { let mut args = vec![opt]; args.extend_from_slice(&test_users); - exp_result = unwrap_or_return!(expected_result(&args)); + exp_result = unwrap_or_return!(expected_result(util_name!(), &args)); scene .ucmd() .args(&args) @@ -94,7 +53,7 @@ fn test_id_single_user() { .stderr_is(exp_result.stderr_str().replace(": Invalid argument", "")) .code_is(exp_result.code()); args.push("--zero"); - exp_result = unwrap_or_return!(expected_result(&args)); + exp_result = unwrap_or_return!(expected_result(util_name!(), &args)); scene .ucmd() .args(&args) @@ -103,7 +62,7 @@ fn test_id_single_user() { .stderr_is(exp_result.stderr_str().replace(": Invalid argument", "")) .code_is(exp_result.code()); args.push("--name"); - exp_result = unwrap_or_return!(expected_result(&args)); + exp_result = unwrap_or_return!(expected_result(util_name!(), &args)); scene .ucmd() .args(&args) @@ -112,7 +71,7 @@ fn test_id_single_user() { .stderr_is(exp_result.stderr_str().replace(": Invalid argument", "")) .code_is(exp_result.code()); args.pop(); - exp_result = unwrap_or_return!(expected_result(&args)); + exp_result = unwrap_or_return!(expected_result(util_name!(), &args)); scene .ucmd() .args(&args) @@ -128,7 +87,7 @@ fn test_id_single_user() { fn test_id_single_user_non_existing() { let args = &["hopefully_non_existing_username"]; let result = new_ucmd!().args(args).run(); - let exp_result = unwrap_or_return!(expected_result(args)); + let exp_result = unwrap_or_return!(expected_result(util_name!(), args)); // It is unknown why on macOS (and possibly others?) `id` adds "Invalid argument". // coreutils 8.32: $ LC_ALL=C id foobar @@ -147,7 +106,7 @@ fn test_id_name() { for &opt in &["--user", "--group", "--groups"] { let args = [opt, "--name"]; let result = scene.ucmd().args(&args).run(); - let exp_result = unwrap_or_return!(expected_result(&args)); + let exp_result = unwrap_or_return!(expected_result(util_name!(), &args)); result .stdout_is(exp_result.stdout_str()) .stderr_is(exp_result.stderr_str()) @@ -166,7 +125,7 @@ fn test_id_real() { for &opt in &["--user", "--group", "--groups"] { let args = [opt, "--real"]; let result = scene.ucmd().args(&args).run(); - let exp_result = unwrap_or_return!(expected_result(&args)); + let exp_result = unwrap_or_return!(expected_result(util_name!(), &args)); result .stdout_is(exp_result.stdout_str()) .stderr_is(exp_result.stderr_str()) @@ -206,21 +165,16 @@ fn test_id_password_style() { #[test] #[cfg(unix)] fn test_id_multiple_users() { - #[cfg(target_os = "linux")] - let util_name = util_name!(); - #[cfg(all(unix, not(target_os = "linux")))] - let util_name = &format!("g{}", util_name!()); - let version_check_string = check_coreutil_version(util_name, VERSION_MIN_MULTIPLE_USERS); - if version_check_string.starts_with(UUTILS_WARNING) { - println!("{}\ntest skipped", version_check_string); - return; - } + unwrap_or_return!(check_coreutil_version( + util_name!(), + VERSION_MIN_MULTIPLE_USERS + )); // Same typical users that GNU test suite is using. let test_users = ["root", "man", "postfix", "sshd", &whoami()]; let scene = TestScenario::new(util_name!()); - let mut exp_result = unwrap_or_return!(expected_result(&test_users)); + let mut exp_result = unwrap_or_return!(expected_result(util_name!(), &test_users)); scene .ucmd() .args(&test_users) @@ -233,7 +187,7 @@ fn test_id_multiple_users() { for &opt in &["--user", "--group", "--groups"] { let mut args = vec![opt]; args.extend_from_slice(&test_users); - exp_result = unwrap_or_return!(expected_result(&args)); + exp_result = unwrap_or_return!(expected_result(util_name!(), &args)); scene .ucmd() .args(&args) @@ -242,7 +196,7 @@ fn test_id_multiple_users() { .stderr_is(exp_result.stderr_str().replace(": Invalid argument", "")) .code_is(exp_result.code()); args.push("--zero"); - exp_result = unwrap_or_return!(expected_result(&args)); + exp_result = unwrap_or_return!(expected_result(util_name!(), &args)); scene .ucmd() .args(&args) @@ -251,7 +205,7 @@ fn test_id_multiple_users() { .stderr_is(exp_result.stderr_str().replace(": Invalid argument", "")) .code_is(exp_result.code()); args.push("--name"); - exp_result = unwrap_or_return!(expected_result(&args)); + exp_result = unwrap_or_return!(expected_result(util_name!(), &args)); scene .ucmd() .args(&args) @@ -260,7 +214,7 @@ fn test_id_multiple_users() { .stderr_is(exp_result.stderr_str().replace(": Invalid argument", "")) .code_is(exp_result.code()); args.pop(); - exp_result = unwrap_or_return!(expected_result(&args)); + exp_result = unwrap_or_return!(expected_result(util_name!(), &args)); scene .ucmd() .args(&args) @@ -274,15 +228,10 @@ fn test_id_multiple_users() { #[test] #[cfg(unix)] fn test_id_multiple_users_non_existing() { - #[cfg(target_os = "linux")] - let util_name = util_name!(); - #[cfg(all(unix, not(target_os = "linux")))] - let util_name = &format!("g{}", util_name!()); - let version_check_string = check_coreutil_version(util_name, VERSION_MIN_MULTIPLE_USERS); - if version_check_string.starts_with(UUTILS_WARNING) { - println!("{}\ntest skipped", version_check_string); - return; - } + unwrap_or_return!(check_coreutil_version( + util_name!(), + VERSION_MIN_MULTIPLE_USERS + )); let test_users = [ "root", @@ -298,7 +247,7 @@ fn test_id_multiple_users_non_existing() { ]; let scene = TestScenario::new(util_name!()); - let mut exp_result = unwrap_or_return!(expected_result(&test_users)); + let mut exp_result = unwrap_or_return!(expected_result(util_name!(), &test_users)); scene .ucmd() .args(&test_users) @@ -311,7 +260,7 @@ fn test_id_multiple_users_non_existing() { for &opt in &["--user", "--group", "--groups"] { let mut args = vec![opt]; args.extend_from_slice(&test_users); - exp_result = unwrap_or_return!(expected_result(&args)); + exp_result = unwrap_or_return!(expected_result(util_name!(), &args)); scene .ucmd() .args(&args) @@ -320,7 +269,7 @@ fn test_id_multiple_users_non_existing() { .stderr_is(exp_result.stderr_str().replace(": Invalid argument", "")) .code_is(exp_result.code()); args.push("--zero"); - exp_result = unwrap_or_return!(expected_result(&args)); + exp_result = unwrap_or_return!(expected_result(util_name!(), &args)); scene .ucmd() .args(&args) @@ -329,7 +278,7 @@ fn test_id_multiple_users_non_existing() { .stderr_is(exp_result.stderr_str().replace(": Invalid argument", "")) .code_is(exp_result.code()); args.push("--name"); - exp_result = unwrap_or_return!(expected_result(&args)); + exp_result = unwrap_or_return!(expected_result(util_name!(), &args)); scene .ucmd() .args(&args) @@ -338,7 +287,7 @@ fn test_id_multiple_users_non_existing() { .stderr_is(exp_result.stderr_str().replace(": Invalid argument", "")) .code_is(exp_result.code()); args.pop(); - exp_result = unwrap_or_return!(expected_result(&args)); + exp_result = unwrap_or_return!(expected_result(util_name!(), &args)); scene .ucmd() .args(&args) @@ -360,12 +309,12 @@ fn test_id_default_format() { .ucmd() .args(&args) .fails() - .stderr_only(unwrap_or_return!(expected_result(&args)).stderr_str()); + .stderr_only(unwrap_or_return!(expected_result(util_name!(), &args)).stderr_str()); for &opt2 in &["--user", "--group", "--groups"] { // u/g/G n/r let args = [opt2, opt1]; let result = scene.ucmd().args(&args).run(); - let exp_result = unwrap_or_return!(expected_result(&args)); + let exp_result = unwrap_or_return!(expected_result(util_name!(), &args)); result .stdout_is(exp_result.stdout_str()) .stderr_is(exp_result.stderr_str()) @@ -379,7 +328,7 @@ fn test_id_default_format() { .ucmd() .args(&args) .succeeds() - .stdout_only(unwrap_or_return!(expected_result(&args)).stdout_str()); + .stdout_only(unwrap_or_return!(expected_result(util_name!(), &args)).stdout_str()); } } @@ -393,7 +342,7 @@ fn test_id_zero() { .ucmd() .args(&[z_flag]) .fails() - .stderr_only(unwrap_or_return!(expected_result(&[z_flag])).stderr_str()); + .stderr_only(unwrap_or_return!(expected_result(util_name!(), &[z_flag])).stderr_str()); for &opt1 in &["--name", "--real"] { // id: cannot print only names or real IDs in default format let args = [opt1, z_flag]; @@ -401,12 +350,12 @@ fn test_id_zero() { .ucmd() .args(&args) .fails() - .stderr_only(unwrap_or_return!(expected_result(&args)).stderr_str()); + .stderr_only(unwrap_or_return!(expected_result(util_name!(), &args)).stderr_str()); for &opt2 in &["--user", "--group", "--groups"] { // u/g/G n/r z let args = [opt2, z_flag, opt1]; let result = scene.ucmd().args(&args).run(); - let exp_result = unwrap_or_return!(expected_result(&args)); + let exp_result = unwrap_or_return!(expected_result(util_name!(), &args)); result .stdout_is(exp_result.stdout_str()) .stderr_is(exp_result.stderr_str()) @@ -420,86 +369,7 @@ fn test_id_zero() { .ucmd() .args(&args) .succeeds() - .stdout_only(unwrap_or_return!(expected_result(&args)).stdout_str()); + .stdout_only(unwrap_or_return!(expected_result(util_name!(), &args)).stdout_str()); } } } - -fn check_coreutil_version(util_name: &str, version_expected: &str) -> String { - // example: - // $ id --version | head -n 1 - // id (GNU coreutils) 8.32.162-4eda - let scene = TestScenario::new(util_name); - let version_check = scene - .cmd_keepenv(&util_name) - .env("LC_ALL", "C") - .arg("--version") - .run(); - version_check - .stdout_str() - .split('\n') - .collect::>() - .get(0) - .map_or_else( - || format!("{}: unexpected output format for reference coreutil: '{} --version'", UUTILS_WARNING, util_name), - |s| { - if s.contains(&format!("(GNU coreutils) {}", version_expected)) { - s.to_string() - } else if s.contains("(GNU coreutils)") { - let version_found = s.split_whitespace().last().unwrap()[..4].parse::().unwrap_or_default(); - let version_expected = version_expected.parse::().unwrap_or_default(); - if version_found > version_expected { - format!("{}: version for the reference coreutil '{}' is higher than expected; expected: {}, found: {}", UUTILS_INFO, util_name, version_expected, version_found) - } else { - format!("{}: version for the reference coreutil '{}' does not match; expected: {}, found: {}", UUTILS_WARNING, util_name, version_expected, version_found) } - } else { - format!("{}: no coreutils version string found for reference coreutils '{} --version'", UUTILS_WARNING, util_name) - } - }, - ) -} - -#[allow(clippy::needless_borrow)] -#[cfg(unix)] -fn expected_result(args: &[&str]) -> Result { - #[cfg(target_os = "linux")] - let util_name = util_name!(); - #[cfg(all(unix, not(target_os = "linux")))] - let util_name = &format!("g{}", util_name!()); - - let version_check_string = check_coreutil_version(util_name, VERSION_MIN); - if version_check_string.starts_with(UUTILS_WARNING) { - return Err(version_check_string); - } - println!("{}", version_check_string); - - let scene = TestScenario::new(util_name); - let result = scene - .cmd_keepenv(util_name) - .env("LC_ALL", "C") - .args(args) - .run(); - - let (stdout, stderr): (String, String) = if cfg!(target_os = "linux") { - ( - result.stdout_str().to_string(), - result.stderr_str().to_string(), - ) - } else { - // strip 'g' prefix from results: - let from = util_name.to_string() + ":"; - let to = &from[1..]; - ( - result.stdout_str().replace(&from, to), - result.stderr_str().replace(&from, to), - ) - }; - - Ok(CmdResult::new( - Some(result.tmpd()), - Some(result.code()), - result.succeeded(), - stdout.as_bytes(), - stderr.as_bytes(), - )) -} From 90de4257b19de89dc7de2a4ca17424a875363d71 Mon Sep 17 00:00:00 2001 From: Jan Scheer Date: Wed, 7 Jul 2021 15:53:46 +0200 Subject: [PATCH 19/25] test_pinky: refactor use expected_result from common/util.rs --- tests/by-util/test_pinky.rs | 35 ++++++++++------------------------- 1 file changed, 10 insertions(+), 25 deletions(-) diff --git a/tests/by-util/test_pinky.rs b/tests/by-util/test_pinky.rs index bc2833a42..3d29bf249 100644 --- a/tests/by-util/test_pinky.rs +++ b/tests/by-util/test_pinky.rs @@ -42,15 +42,17 @@ fn test_long_format() { )); } -#[cfg(any(target_vendor = "apple", target_os = "linux"))] +#[cfg(unix)] #[test] fn test_long_format_multiple_users() { let args = ["-l", "root", "root", "root"]; + let expect = unwrap_or_return!(expected_result(util_name!(), &args)); new_ucmd!() .args(&args) .succeeds() - .stdout_is(expected_result(&args)); + .stdout_is(expect.stdout_str()) + .stderr_is(expect.stderr_str()); } #[test] @@ -59,55 +61,38 @@ fn test_long_format_wo_user() { new_ucmd!().arg("-l").fails().code_is(1); } -#[cfg(any(target_vendor = "apple", target_os = "linux"))] +#[cfg(unix)] #[test] fn test_short_format_i() { // allow whitespace variation // * minor whitespace differences occur between platform built-in outputs; specifically, the number of trailing TABs may be variant let args = ["-i"]; let actual = new_ucmd!().args(&args).succeeds().stdout_move_str(); - let expect = expected_result(&args); + let expect = unwrap_or_return!(expected_result(util_name!(), &args)).stdout_move_str(); let v_actual: Vec<&str> = actual.split_whitespace().collect(); let v_expect: Vec<&str> = expect.split_whitespace().collect(); assert_eq!(v_actual, v_expect); } -#[cfg(any(target_vendor = "apple", target_os = "linux"))] +#[cfg(unix)] #[test] fn test_short_format_q() { // allow whitespace variation // * minor whitespace differences occur between platform built-in outputs; specifically, the number of trailing TABs may be variant let args = ["-q"]; let actual = new_ucmd!().args(&args).succeeds().stdout_move_str(); - let expect = expected_result(&args); + let expect = unwrap_or_return!(expected_result(util_name!(), &args)).stdout_move_str(); let v_actual: Vec<&str> = actual.split_whitespace().collect(); let v_expect: Vec<&str> = expect.split_whitespace().collect(); assert_eq!(v_actual, v_expect); } -#[cfg(any(target_vendor = "apple", target_os = "linux"))] +#[cfg(unix)] #[test] fn test_no_flag() { let actual = new_ucmd!().succeeds().stdout_move_str(); - let expect = expected_result(&[]); + let expect = unwrap_or_return!(expected_result(util_name!(), &[])).stdout_move_str(); let v_actual: Vec<&str> = actual.split_whitespace().collect(); let v_expect: Vec<&str> = expect.split_whitespace().collect(); assert_eq!(v_actual, v_expect); } - -#[cfg(any(target_vendor = "apple", target_os = "linux"))] -fn expected_result(args: &[&str]) -> String { - #[cfg(target_os = "linux")] - let util_name = util_name!(); - #[cfg(target_vendor = "apple")] - let util_name = format!("g{}", util_name!()); - - // note: clippy::needless_borrow *false positive* - #[allow(clippy::needless_borrow)] - TestScenario::new(&util_name) - .cmd_keepenv(util_name) - .env("LC_ALL", "C") - .args(args) - .succeeds() - .stdout_move_str() -} From 805e024794636a45effa64a5e29178db61356c52 Mon Sep 17 00:00:00 2001 From: Jan Scheer Date: Wed, 7 Jul 2021 15:54:03 +0200 Subject: [PATCH 20/25] test_stat: refactor use expected_result from common/util.rs --- tests/by-util/test_stat.rs | 69 ++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 41 deletions(-) diff --git a/tests/by-util/test_stat.rs b/tests/by-util/test_stat.rs index ddf78815f..ec85f8f27 100644 --- a/tests/by-util/test_stat.rs +++ b/tests/by-util/test_stat.rs @@ -109,30 +109,26 @@ const FS_FORMAT_STR: &str = "%b %c %i %l %n %s %S %t %T"; // avoid "%a %d %f" wh #[cfg(target_os = "linux")] fn test_terse_fs_format() { let args = ["-f", "-t", "/proc"]; - new_ucmd!() - .args(&args) - .run() - .stdout_is(expected_result(&args)); + let expected_stdout = unwrap_or_return!(expected_result(util_name!(), &args)).stdout_move_str(); + new_ucmd!().args(&args).run().stdout_is(expected_stdout); } #[test] #[cfg(target_os = "linux")] fn test_fs_format() { let args = ["-f", "-c", FS_FORMAT_STR, "/dev/shm"]; - new_ucmd!() - .args(&args) - .run() - .stdout_is(expected_result(&args)); + let expected_stdout = unwrap_or_return!(expected_result(util_name!(), &args)).stdout_move_str(); + new_ucmd!().args(&args).run().stdout_is(expected_stdout); } -#[cfg(any(target_os = "linux", target_vendor = "apple"))] +#[cfg(unix)] #[test] fn test_terse_normal_format() { // note: contains birth/creation date which increases test fragility // * results may vary due to built-in `stat` limitations as well as linux kernel and rust version capability variations let args = ["-t", "/"]; let actual = new_ucmd!().args(&args).succeeds().stdout_move_str(); - let expect = expected_result(&args); + let expect = unwrap_or_return!(expected_result(util_name!(), &args)).stdout_move_str(); println!("actual: {:?}", actual); println!("expect: {:?}", expect); let v_actual: Vec<&str> = actual.trim().split(' ').collect(); @@ -156,12 +152,12 @@ fn test_terse_normal_format() { ); } -#[cfg(any(target_os = "linux", target_vendor = "apple"))] +#[cfg(unix)] #[test] fn test_format_created_time() { let args = ["-c", "%w", "/bin"]; let actual = new_ucmd!().args(&args).succeeds().stdout_move_str(); - let expect = expected_result(&args); + let expect = unwrap_or_return!(expected_result(util_name!(), &args)).stdout_move_str(); println!("actual: {:?}", actual); println!("expect: {:?}", expect); // note: using a regex instead of `split_whitespace()` in order to detect whitespace differences @@ -180,12 +176,12 @@ fn test_format_created_time() { ); } -#[cfg(any(target_os = "linux", target_vendor = "apple"))] +#[cfg(unix)] #[test] fn test_format_created_seconds() { let args = ["-c", "%W", "/bin"]; let actual = new_ucmd!().args(&args).succeeds().stdout_move_str(); - let expect = expected_result(&args); + let expect = unwrap_or_return!(expected_result(util_name!(), &args)).stdout_move_str(); println!("actual: {:?}", actual); println!("expect: {:?}", expect); // note: using a regex instead of `split_whitespace()` in order to detect whitespace differences @@ -204,17 +200,18 @@ fn test_format_created_seconds() { ); } -#[cfg(any(target_os = "linux", target_vendor = "apple"))] +#[cfg(unix)] #[test] fn test_normal_format() { let args = ["-c", NORMAL_FORMAT_STR, "/bin"]; + let expected_stdout = unwrap_or_return!(expected_result(util_name!(), &args)).stdout_move_str(); new_ucmd!() .args(&args) .succeeds() - .stdout_is(expected_result(&args)); + .stdout_is(expected_stdout); } -#[cfg(any(target_os = "linux", target_vendor = "apple"))] +#[cfg(unix)] #[test] fn test_symlinks() { let scene = TestScenario::new(util_name!()); @@ -232,18 +229,22 @@ fn test_symlinks() { if at.file_exists(file) && at.is_symlink(file) { tested = true; let args = ["-c", NORMAL_FORMAT_STR, file]; + let expected_stdout = + unwrap_or_return!(expected_result(util_name!(), &args)).stdout_move_str(); scene .ucmd() .args(&args) .succeeds() - .stdout_is(expected_result(&args)); + .stdout_is(expected_stdout); // -L, --dereference follow links let args = ["-L", "-c", NORMAL_FORMAT_STR, file]; + let expected_stdout = + unwrap_or_return!(expected_result(util_name!(), &args)).stdout_move_str(); scene .ucmd() .args(&args) .succeeds() - .stdout_is(expected_result(&args)); + .stdout_is(expected_stdout); } } if !tested { @@ -269,13 +270,14 @@ fn test_char() { #[cfg(any(target_vendor = "apple"))] "/dev/ptmx", ]; + let expected_stdout = unwrap_or_return!(expected_result(util_name!(), &args)).stdout_move_str(); new_ucmd!() .args(&args) .succeeds() - .stdout_is(expected_result(&args)); + .stdout_is(expected_stdout); } -#[cfg(any(target_os = "linux", target_vendor = "apple"))] +#[cfg(unix)] #[test] fn test_multi_files() { let args = [ @@ -287,38 +289,23 @@ fn test_multi_files() { "/etc/fstab", "/var", ]; + let expected_stdout = unwrap_or_return!(expected_result(util_name!(), &args)).stdout_move_str(); new_ucmd!() .args(&args) .succeeds() - .stdout_is(expected_result(&args)); + .stdout_is(expected_stdout); } -#[cfg(any(target_vendor = "apple", target_os = "linux"))] +#[cfg(unix)] #[test] fn test_printf() { let args = [ "--printf=123%-# 15q\\r\\\"\\\\\\a\\b\\e\\f\\v%+020.23m\\x12\\167\\132\\112\\n", "/", ]; + let expected_stdout = unwrap_or_return!(expected_result(util_name!(), &args)).stdout_move_str(); new_ucmd!() .args(&args) .succeeds() - .stdout_is(expected_result(&args)); -} - -#[cfg(any(target_vendor = "apple", target_os = "linux"))] -fn expected_result(args: &[&str]) -> String { - #[cfg(target_os = "linux")] - let util_name = util_name!(); - #[cfg(target_vendor = "apple")] - let util_name = format!("g{}", util_name!()); - - // note: clippy::needless_borrow *false positive* - #[allow(clippy::needless_borrow)] - TestScenario::new(&util_name) - .cmd_keepenv(util_name) - .env("LC_ALL", "C") - .args(args) - .succeeds() - .stdout_move_str() + .stdout_is(expected_stdout); } From 735ec4014e1cab2cd7417e928e64e6159fd0b8bb Mon Sep 17 00:00:00 2001 From: Jan Scheer Date: Wed, 7 Jul 2021 16:19:58 +0200 Subject: [PATCH 21/25] test_who: refactor use expected_result from common/util.rs --- tests/by-util/test_groups.rs | 5 ++ tests/by-util/test_id.rs | 7 +- tests/by-util/test_pinky.rs | 5 ++ tests/by-util/test_stat.rs | 5 ++ tests/by-util/test_who.rs | 153 +++++++++++++++-------------------- tests/common/macros.rs | 5 ++ tests/common/util.rs | 5 ++ 7 files changed, 98 insertions(+), 87 deletions(-) diff --git a/tests/by-util/test_groups.rs b/tests/by-util/test_groups.rs index 9cebdf878..52ac00a0d 100644 --- a/tests/by-util/test_groups.rs +++ b/tests/by-util/test_groups.rs @@ -1,3 +1,8 @@ +// * This file is part of the uutils coreutils package. +// * +// * For the full copyright and license information, please view the LICENSE +// * file that was distributed with this source code. + use crate::common::util::*; const VERSION_MIN_MULTIPLE_USERS: &str = "8.31"; // this feature was introduced in GNU's coreutils 8.31 diff --git a/tests/by-util/test_id.rs b/tests/by-util/test_id.rs index 6c6f168fe..e491236d8 100644 --- a/tests/by-util/test_id.rs +++ b/tests/by-util/test_id.rs @@ -1,7 +1,12 @@ -use crate::common::util::*; +// * This file is part of the uutils coreutils package. +// * +// * For the full copyright and license information, please view the LICENSE +// * file that was distributed with this source code. // spell-checker:ignore (ToDO) coreutil +use crate::common::util::*; + const VERSION_MIN_MULTIPLE_USERS: &str = "8.31"; // this feature was introduced in GNU's coreutils 8.31 #[test] diff --git a/tests/by-util/test_pinky.rs b/tests/by-util/test_pinky.rs index 3d29bf249..220fd9108 100644 --- a/tests/by-util/test_pinky.rs +++ b/tests/by-util/test_pinky.rs @@ -1,3 +1,8 @@ +// * This file is part of the uutils coreutils package. +// * +// * For the full copyright and license information, please view the LICENSE +// * file that was distributed with this source code. + extern crate uucore; use crate::common::util::*; diff --git a/tests/by-util/test_stat.rs b/tests/by-util/test_stat.rs index ec85f8f27..2e0551ec5 100644 --- a/tests/by-util/test_stat.rs +++ b/tests/by-util/test_stat.rs @@ -1,3 +1,8 @@ +// * This file is part of the uutils coreutils package. +// * +// * For the full copyright and license information, please view the LICENSE +// * file that was distributed with this source code. + extern crate regex; use crate::common::util::*; diff --git a/tests/by-util/test_who.rs b/tests/by-util/test_who.rs index 9315a5956..c84ad0f2f 100644 --- a/tests/by-util/test_who.rs +++ b/tests/by-util/test_who.rs @@ -1,30 +1,33 @@ -use crate::common::util::*; +// * This file is part of the uutils coreutils package. +// * +// * For the full copyright and license information, please view the LICENSE +// * file that was distributed with this source code. // spell-checker:ignore (flags) runlevel mesg -#[cfg(any(target_vendor = "apple", target_os = "linux"))] +use crate::common::util::*; + +#[cfg(unix)] #[test] fn test_count() { for opt in &["-q", "--count"] { - new_ucmd!() - .arg(opt) - .succeeds() - .stdout_is(expected_result(&[opt])); + let expected_stdout = + unwrap_or_return!(expected_result(util_name!(), &[opt])).stdout_move_str(); + new_ucmd!().arg(opt).succeeds().stdout_is(expected_stdout); } } -#[cfg(any(target_vendor = "apple", target_os = "linux"))] +#[cfg(unix)] #[test] fn test_boot() { for opt in &["-b", "--boot"] { - new_ucmd!() - .arg(opt) - .succeeds() - .stdout_is(expected_result(&[opt])); + let expected_stdout = + unwrap_or_return!(expected_result(util_name!(), &[opt])).stdout_move_str(); + new_ucmd!().arg(opt).succeeds().stdout_is(expected_stdout); } } -#[cfg(any(target_vendor = "apple", target_os = "linux"))] +#[cfg(unix)] #[test] fn test_heading() { for opt in &["-H", "--heading"] { @@ -32,7 +35,7 @@ fn test_heading() { // * minor whitespace differences occur between platform built-in outputs; // specifically number of TABs between "TIME" and "COMMENT" may be variant let actual = new_ucmd!().arg(opt).succeeds().stdout_move_str(); - let expect = expected_result(&[opt]); + let expect = unwrap_or_return!(expected_result(util_name!(), &[opt])).stdout_move_str(); println!("actual: {:?}", actual); println!("expect: {:?}", expect); let v_actual: Vec<&str> = actual.split_whitespace().collect(); @@ -41,76 +44,70 @@ fn test_heading() { } } -#[cfg(any(target_vendor = "apple", target_os = "linux"))] +#[cfg(unix)] #[test] fn test_short() { for opt in &["-s", "--short"] { - new_ucmd!() - .arg(opt) - .succeeds() - .stdout_is(expected_result(&[opt])); + let expected_stdout = + unwrap_or_return!(expected_result(util_name!(), &[opt])).stdout_move_str(); + new_ucmd!().arg(opt).succeeds().stdout_is(expected_stdout); } } -#[cfg(any(target_vendor = "apple", target_os = "linux"))] +#[cfg(unix)] #[test] fn test_login() { for opt in &["-l", "--login"] { - new_ucmd!() - .arg(opt) - .succeeds() - .stdout_is(expected_result(&[opt])); + let expected_stdout = + unwrap_or_return!(expected_result(util_name!(), &[opt])).stdout_move_str(); + new_ucmd!().arg(opt).succeeds().stdout_is(expected_stdout); } } -#[cfg(any(target_vendor = "apple", target_os = "linux"))] +#[cfg(unix)] #[test] fn test_m() { for opt in &["-m"] { - new_ucmd!() - .arg(opt) - .succeeds() - .stdout_is(expected_result(&[opt])); + let expected_stdout = + unwrap_or_return!(expected_result(util_name!(), &[opt])).stdout_move_str(); + new_ucmd!().arg(opt).succeeds().stdout_is(expected_stdout); } } -#[cfg(any(target_vendor = "apple", target_os = "linux"))] +#[cfg(unix)] #[test] fn test_process() { for opt in &["-p", "--process"] { - new_ucmd!() - .arg(opt) - .succeeds() - .stdout_is(expected_result(&[opt])); + let expected_stdout = + unwrap_or_return!(expected_result(util_name!(), &[opt])).stdout_move_str(); + new_ucmd!().arg(opt).succeeds().stdout_is(expected_stdout); } } +#[cfg(unix)] #[test] fn test_runlevel() { for opt in &["-r", "--runlevel"] { - #[cfg(any(target_vendor = "apple", target_os = "linux"))] - new_ucmd!() - .arg(opt) - .succeeds() - .stdout_is(expected_result(&[opt])); + let expected_stdout = + unwrap_or_return!(expected_result(util_name!(), &[opt])).stdout_move_str(); + new_ucmd!().arg(opt).succeeds().stdout_is(expected_stdout); #[cfg(not(target_os = "linux"))] new_ucmd!().arg(opt).succeeds().stdout_is(""); } } -#[cfg(any(target_vendor = "apple", target_os = "linux"))] +#[cfg(unix)] #[test] fn test_time() { for opt in &["-t", "--time"] { - new_ucmd!() - .arg(opt) - .succeeds() - .stdout_is(expected_result(&[opt])); + let expected_stdout = + unwrap_or_return!(expected_result(util_name!(), &[opt])).stdout_move_str(); + new_ucmd!().arg(opt).succeeds().stdout_is(expected_stdout); } } -#[cfg(any(target_vendor = "apple", target_os = "linux"))] +#[cfg(unix)] #[test] fn test_mesg() { // -T, -w, --mesg @@ -120,21 +117,22 @@ fn test_mesg() { // --writable // same as -T for opt in &["-T", "-w", "--mesg", "--message", "--writable"] { - new_ucmd!() - .arg(opt) - .succeeds() - .stdout_is(expected_result(&[opt])); + let expected_stdout = + unwrap_or_return!(expected_result(util_name!(), &[opt])).stdout_move_str(); + new_ucmd!().arg(opt).succeeds().stdout_is(expected_stdout); } } +#[cfg(unix)] #[test] fn test_arg1_arg2() { let args = ["am", "i"]; + let expected_stdout = unwrap_or_return!(expected_result(util_name!(), &args)).stdout_move_str(); new_ucmd!() .args(&args) .succeeds() - .stdout_is(expected_result(&args)); + .stdout_is(expected_stdout); } #[test] @@ -146,12 +144,12 @@ fn test_too_many_args() { new_ucmd!().args(&args).fails().stderr_contains(EXPECTED); } -#[cfg(any(target_vendor = "apple", target_os = "linux"))] +#[cfg(unix)] #[test] fn test_users() { for opt in &["-u", "--users"] { let actual = new_ucmd!().arg(opt).succeeds().stdout_move_str(); - let expect = expected_result(&[opt]); + let expect = unwrap_or_return!(expected_result(util_name!(), &[opt])).stdout_move_str(); println!("actual: {:?}", actual); println!("expect: {:?}", expect); @@ -170,28 +168,26 @@ fn test_users() { } } -#[cfg(any(target_vendor = "apple", target_os = "linux"))] +#[cfg(unix)] #[test] fn test_lookup() { let opt = "--lookup"; - new_ucmd!() - .arg(opt) - .succeeds() - .stdout_is(expected_result(&[opt])); + let expected_stdout = + unwrap_or_return!(expected_result(util_name!(), &[opt])).stdout_move_str(); + new_ucmd!().arg(opt).succeeds().stdout_is(expected_stdout); } -#[cfg(any(target_vendor = "apple", target_os = "linux"))] +#[cfg(unix)] #[test] fn test_dead() { for opt in &["-d", "--dead"] { - new_ucmd!() - .arg(opt) - .succeeds() - .stdout_is(expected_result(&[opt])); + let expected_stdout = + unwrap_or_return!(expected_result(util_name!(), &[opt])).stdout_move_str(); + new_ucmd!().arg(opt).succeeds().stdout_is(expected_stdout); } } -#[cfg(any(target_vendor = "apple", target_os = "linux"))] +#[cfg(unix)] #[test] fn test_all_separately() { if cfg!(target_os = "macos") { @@ -201,20 +197,23 @@ fn test_all_separately() { // -a, --all same as -b -d --login -p -r -t -T -u let args = ["-b", "-d", "--login", "-p", "-r", "-t", "-T", "-u"]; + let expected_stdout = unwrap_or_return!(expected_result(util_name!(), &args)).stdout_move_str(); let scene = TestScenario::new(util_name!()); scene .ucmd() .args(&args) .succeeds() - .stdout_is(expected_result(&args)); + .stdout_is(expected_stdout); + let expected_stdout = + unwrap_or_return!(expected_result(util_name!(), &["--all"])).stdout_move_str(); scene .ucmd() .arg("--all") .succeeds() - .stdout_is(expected_result(&args)); + .stdout_is(expected_stdout); } -#[cfg(any(target_vendor = "apple", target_os = "linux"))] +#[cfg(unix)] #[test] fn test_all() { if cfg!(target_os = "macos") { @@ -223,26 +222,8 @@ fn test_all() { } for opt in &["-a", "--all"] { - new_ucmd!() - .arg(opt) - .succeeds() - .stdout_is(expected_result(&[opt])); + let expected_stdout = + unwrap_or_return!(expected_result(util_name!(), &[opt])).stdout_move_str(); + new_ucmd!().arg(opt).succeeds().stdout_is(expected_stdout); } } - -#[cfg(any(target_vendor = "apple", target_os = "linux"))] -fn expected_result(args: &[&str]) -> String { - #[cfg(target_os = "linux")] - let util_name = util_name!(); - #[cfg(target_vendor = "apple")] - let util_name = format!("g{}", util_name!()); - - // note: clippy::needless_borrow *false positive* - #[allow(clippy::needless_borrow)] - TestScenario::new(&util_name) - .cmd_keepenv(util_name) - .env("LC_ALL", "C") - .args(args) - .succeeds() - .stdout_move_str() -} diff --git a/tests/common/macros.rs b/tests/common/macros.rs index 2a1c20af2..62b8c4824 100644 --- a/tests/common/macros.rs +++ b/tests/common/macros.rs @@ -1,3 +1,8 @@ +// * This file is part of the uutils coreutils package. +// * +// * For the full copyright and license information, please view the LICENSE +// * file that was distributed with this source code. + /// Platform-independent helper for constructing a PathBuf from individual elements #[macro_export] macro_rules! path_concat { diff --git a/tests/common/util.rs b/tests/common/util.rs index 79af471e3..2cff46224 100644 --- a/tests/common/util.rs +++ b/tests/common/util.rs @@ -1,3 +1,8 @@ +// * This file is part of the uutils coreutils package. +// * +// * For the full copyright and license information, please view the LICENSE +// * file that was distributed with this source code. + //spell-checker: ignore (linux) rlimit prlimit Rlim coreutil #![allow(dead_code)] From 31aa8b206299a3bc8e711c00e428b40aa2bd8599 Mon Sep 17 00:00:00 2001 From: Jan Scheer Date: Wed, 7 Jul 2021 22:09:01 +0200 Subject: [PATCH 22/25] test_du: refactor use expected_result from common/util.rs --- tests/by-util/test_du.rs | 117 +++++++++++++++++++-------------------- 1 file changed, 56 insertions(+), 61 deletions(-) diff --git a/tests/by-util/test_du.rs b/tests/by-util/test_du.rs index 029f5e516..607d5dc45 100644 --- a/tests/by-util/test_du.rs +++ b/tests/by-util/test_du.rs @@ -39,13 +39,13 @@ fn _du_basics(s: &str) { #[test] fn test_du_basics_subdir() { - let scene = TestScenario::new(util_name!()); + let ts = TestScenario::new(util_name!()); - let result = scene.ucmd().arg(SUB_DIR).succeeds(); + let result = ts.ucmd().arg(SUB_DIR).succeeds(); #[cfg(target_os = "linux")] { - let result_reference = scene.cmd("du").arg(SUB_DIR).run(); + let result_reference = unwrap_or_return!(expected_result(&ts, &[SUB_DIR])); if result_reference.succeeded() { assert_eq!(result.stdout_str(), result_reference.stdout_str()); return; @@ -83,15 +83,16 @@ fn _du_basics_subdir(s: &str) { #[test] fn test_du_invalid_size() { let args = &["block-size", "threshold"]; + let ts = TestScenario::new(util_name!()); for s in args { - new_ucmd!() + ts.ucmd() .arg(format!("--{}=1fb4t", s)) .arg("/tmp") .fails() .code_is(1) .stderr_only(format!("du: invalid --{} argument '1fb4t'", s)); #[cfg(not(target_pointer_width = "128"))] - new_ucmd!() + ts.ucmd() .arg(format!("--{}=1Y", s)) .arg("/tmp") .fails() @@ -110,16 +111,16 @@ fn test_du_basics_bad_name() { #[test] fn test_du_soft_link() { - let scene = TestScenario::new(util_name!()); - let at = &scene.fixtures; + let ts = TestScenario::new(util_name!()); + let at = &ts.fixtures; at.symlink_file(SUB_FILE, SUB_LINK); - let result = scene.ucmd().arg(SUB_DIR_LINKS).succeeds(); + let result = ts.ucmd().arg(SUB_DIR_LINKS).succeeds(); #[cfg(target_os = "linux")] { - let result_reference = scene.cmd("du").arg(SUB_DIR_LINKS).run(); + let result_reference = unwrap_or_return!(expected_result(&ts, &[SUB_DIR_LINKS])); if result_reference.succeeded() { assert_eq!(result.stdout_str(), result_reference.stdout_str()); return; @@ -157,16 +158,16 @@ fn _du_soft_link(s: &str) { #[test] fn test_du_hard_link() { - let scene = TestScenario::new(util_name!()); - let at = &scene.fixtures; + let ts = TestScenario::new(util_name!()); + let at = &ts.fixtures; at.hard_link(SUB_FILE, SUB_LINK); - let result = scene.ucmd().arg(SUB_DIR_LINKS).succeeds(); + let result = ts.ucmd().arg(SUB_DIR_LINKS).succeeds(); #[cfg(target_os = "linux")] { - let result_reference = scene.cmd("du").arg(SUB_DIR_LINKS).run(); + let result_reference = unwrap_or_return!(expected_result(&ts, &[SUB_DIR_LINKS])); if result_reference.succeeded() { assert_eq!(result.stdout_str(), result_reference.stdout_str()); return; @@ -204,13 +205,13 @@ fn _du_hard_link(s: &str) { #[test] fn test_du_d_flag() { - let scene = TestScenario::new(util_name!()); + let ts = TestScenario::new(util_name!()); - let result = scene.ucmd().arg("-d1").succeeds(); + let result = ts.ucmd().arg("-d1").succeeds(); #[cfg(target_os = "linux")] { - let result_reference = scene.cmd("du").arg("-d1").run(); + let result_reference = unwrap_or_return!(expected_result(&ts, &["-d1"])); if result_reference.succeeded() { assert_eq!(result.stdout_str(), result_reference.stdout_str()); return; @@ -247,16 +248,17 @@ fn _du_d_flag(s: &str) { #[test] fn test_du_dereference() { - let scene = TestScenario::new(util_name!()); - let at = &scene.fixtures; + let ts = TestScenario::new(util_name!()); + let at = &ts.fixtures; at.symlink_dir(SUB_DEEPER_DIR, SUB_DIR_LINKS_DEEPER_SYM_DIR); - let result = scene.ucmd().arg("-L").arg(SUB_DIR_LINKS).succeeds(); + let result = ts.ucmd().arg("-L").arg(SUB_DIR_LINKS).succeeds(); #[cfg(target_os = "linux")] { - let result_reference = scene.cmd("du").arg("-L").arg(SUB_DIR_LINKS).run(); + let result_reference = unwrap_or_return!(expected_result(&ts, &["-L", SUB_DIR_LINKS])); + if result_reference.succeeded() { assert_eq!(result.stdout_str(), result_reference.stdout_str()); return; @@ -294,12 +296,12 @@ fn _du_dereference(s: &str) { #[test] fn test_du_inodes_basic() { - let scene = TestScenario::new(util_name!()); - let result = scene.ucmd().arg("--inodes").succeeds(); + let ts = TestScenario::new(util_name!()); + let result = ts.ucmd().arg("--inodes").succeeds(); #[cfg(target_os = "linux")] { - let result_reference = scene.cmd("du").arg("--inodes").run(); + let result_reference = unwrap_or_return!(expected_result(&ts, &["--inodes"])); assert_eq!(result.stdout_str(), result_reference.stdout_str()); } @@ -335,20 +337,15 @@ fn _du_inodes_basic(s: &str) { #[test] fn test_du_inodes() { - let scene = TestScenario::new(util_name!()); + let ts = TestScenario::new(util_name!()); - scene - .ucmd() + ts.ucmd() .arg("--summarize") .arg("--inodes") .succeeds() .stdout_only("11\t.\n"); - let result = scene - .ucmd() - .arg("--separate-dirs") - .arg("--inodes") - .succeeds(); + let result = ts.ucmd().arg("--separate-dirs").arg("--inodes").succeeds(); #[cfg(target_os = "windows")] result.stdout_contains("3\t.\\subdir\\links\n"); @@ -358,7 +355,8 @@ fn test_du_inodes() { #[cfg(target_os = "linux")] { - let result_reference = scene.cmd("du").arg("--separate-dirs").arg("--inodes").run(); + let result_reference = + unwrap_or_return!(expected_result(&ts, &["--separate-dirs", "--inodes"])); assert_eq!(result.stdout_str(), result_reference.stdout_str()); } } @@ -375,31 +373,29 @@ fn test_du_h_flag_empty_file() { #[cfg(feature = "touch")] #[test] fn test_du_time() { - let scene = TestScenario::new(util_name!()); + let ts = TestScenario::new(util_name!()); - scene - .ccmd("touch") + ts.ccmd("touch") .arg("-a") .arg("-t") .arg("201505150000") .arg("date_test") .succeeds(); - scene - .ccmd("touch") + ts.ccmd("touch") .arg("-m") .arg("-t") .arg("201606160000") .arg("date_test") .succeeds(); - let result = scene.ucmd().arg("--time").arg("date_test").succeeds(); + let result = ts.ucmd().arg("--time").arg("date_test").succeeds(); result.stdout_only("0\t2016-06-16 00:00\tdate_test\n"); - let result = scene.ucmd().arg("--time=atime").arg("date_test").succeeds(); + let result = ts.ucmd().arg("--time=atime").arg("date_test").succeeds(); result.stdout_only("0\t2015-05-15 00:00\tdate_test\n"); - let result = scene.ucmd().arg("--time=ctime").arg("date_test").succeeds(); + let result = ts.ucmd().arg("--time=ctime").arg("date_test").succeeds(); result.stdout_only("0\t2016-06-16 00:00\tdate_test\n"); #[cfg(not(target_env = "musl"))] @@ -408,7 +404,7 @@ fn test_du_time() { let re_birth = Regex::new(r"0\t[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}\tdate_test").unwrap(); - let result = scene.ucmd().arg("--time=birth").arg("date_test").succeeds(); + let result = ts.ucmd().arg("--time=birth").arg("date_test").succeeds(); result.stdout_matches(&re_birth); } } @@ -417,21 +413,21 @@ fn test_du_time() { #[cfg(feature = "chmod")] #[test] fn test_du_no_permission() { - let scene = TestScenario::new(util_name!()); - let at = &scene.fixtures; + let ts = TestScenario::new(util_name!()); + let at = &ts.fixtures; at.mkdir_all(SUB_DIR_LINKS); - scene.ccmd("chmod").arg("-r").arg(SUB_DIR_LINKS).succeeds(); + ts.ccmd("chmod").arg("-r").arg(SUB_DIR_LINKS).succeeds(); - let result = scene.ucmd().arg(SUB_DIR_LINKS).run(); // TODO: replace with ".fails()" once `du` is fixed + let result = ts.ucmd().arg(SUB_DIR_LINKS).run(); // TODO: replace with ".fails()" once `du` is fixed result.stderr_contains( "du: cannot read directory 'subdir/links': Permission denied (os error 13)", ); #[cfg(target_os = "linux")] { - let result_reference = scene.cmd("du").arg(SUB_DIR_LINKS).fails(); + let result_reference = unwrap_or_return!(expected_result(&ts, &[SUB_DIR_LINKS])); if result_reference .stderr_str() .contains("du: cannot read directory 'subdir/links': Permission denied") @@ -455,13 +451,13 @@ fn _du_no_permission(s: &str) { #[test] fn test_du_one_file_system() { - let scene = TestScenario::new(util_name!()); + let ts = TestScenario::new(util_name!()); - let result = scene.ucmd().arg("-x").arg(SUB_DIR).succeeds(); + let result = ts.ucmd().arg("-x").arg(SUB_DIR).succeeds(); #[cfg(target_os = "linux")] { - let result_reference = scene.cmd("du").arg("-x").arg(SUB_DIR).run(); + let result_reference = unwrap_or_return!(expected_result(&ts, &["-x", SUB_DIR])); if result_reference.succeeded() { assert_eq!(result.stdout_str(), result_reference.stdout_str()); return; @@ -472,19 +468,17 @@ fn test_du_one_file_system() { #[test] fn test_du_threshold() { - let scene = TestScenario::new(util_name!()); + let ts = TestScenario::new(util_name!()); let threshold = if cfg!(windows) { "7K" } else { "10K" }; - scene - .ucmd() + ts.ucmd() .arg(format!("--threshold={}", threshold)) .succeeds() .stdout_contains("links") .stdout_does_not_contain("deeper_dir"); - scene - .ucmd() + ts.ucmd() .arg(format!("--threshold=-{}", threshold)) .succeeds() .stdout_does_not_contain("links") @@ -493,12 +487,12 @@ fn test_du_threshold() { #[test] fn test_du_apparent_size() { - let scene = TestScenario::new(util_name!()); - let result = scene.ucmd().arg("--apparent-size").succeeds(); + let ts = TestScenario::new(util_name!()); + let result = ts.ucmd().arg("--apparent-size").succeeds(); #[cfg(target_os = "linux")] { - let result_reference = scene.cmd("du").arg("--apparent-size").run(); + let result_reference = unwrap_or_return!(expected_result(&ts, &["--apparent-size"])); assert_eq!(result.stdout_str(), result_reference.stdout_str()); } @@ -561,12 +555,12 @@ fn _du_apparent_size(s: &str) { #[test] fn test_du_bytes() { - let scene = TestScenario::new(util_name!()); - let result = scene.ucmd().arg("--bytes").succeeds(); + let ts = TestScenario::new(util_name!()); + let result = ts.ucmd().arg("--bytes").succeeds(); #[cfg(target_os = "linux")] { - let result_reference = scene.cmd("du").arg("--bytes").run(); + let result_reference = unwrap_or_return!(expected_result(&ts, &["--bytes"])); assert_eq!(result.stdout_str(), result_reference.stdout_str()); } @@ -579,7 +573,8 @@ fn test_du_bytes() { #[cfg(all( not(target_vendor = "apple"), not(target_os = "windows"), - not(target_os = "freebsd") + not(target_os = "freebsd"), + not(target_os = "linux") ))] result.stdout_contains("21529\t./subdir\n"); } From abc59fbe8544845a66eb81ee14bffadd3476da40 Mon Sep 17 00:00:00 2001 From: Jan Scheer Date: Wed, 7 Jul 2021 22:46:16 +0200 Subject: [PATCH 23/25] tests/common: refactor: use TestScenario instead of util_name for expected_result() --- tests/by-util/test_groups.rs | 15 ++-- tests/by-util/test_id.rs | 143 ++++++++++++++++------------------- tests/by-util/test_pinky.rs | 41 +++++----- tests/by-util/test_stat.rs | 79 ++++++++----------- tests/by-util/test_who.rs | 112 +++++++++++++-------------- tests/common/util.rs | 20 ++--- 6 files changed, 189 insertions(+), 221 deletions(-) diff --git a/tests/by-util/test_groups.rs b/tests/by-util/test_groups.rs index 52ac00a0d..14e5a356d 100644 --- a/tests/by-util/test_groups.rs +++ b/tests/by-util/test_groups.rs @@ -10,8 +10,9 @@ const VERSION_MIN_MULTIPLE_USERS: &str = "8.31"; // this feature was introduced #[test] #[cfg(unix)] fn test_groups() { - let result = new_ucmd!().run(); - let exp_result = unwrap_or_return!(expected_result(util_name!(), &[])); + let ts = TestScenario::new(util_name!()); + let result = ts.ucmd().run(); + let exp_result = unwrap_or_return!(expected_result(&ts, &[])); result .stdout_is(exp_result.stdout_str()) @@ -24,8 +25,9 @@ fn test_groups() { fn test_groups_username() { let test_users = [&whoami()[..]]; - let result = new_ucmd!().args(&test_users).run(); - let exp_result = unwrap_or_return!(expected_result(util_name!(), &test_users)); + let ts = TestScenario::new(util_name!()); + let result = ts.ucmd().args(&test_users).run(); + let exp_result = unwrap_or_return!(expected_result(&ts, &test_users)); result .stdout_is(exp_result.stdout_str()) @@ -42,8 +44,9 @@ fn test_groups_username_multiple() { )); let test_users = ["root", "man", "postfix", "sshd", &whoami()]; - let result = new_ucmd!().args(&test_users).run(); - let exp_result = unwrap_or_return!(expected_result(util_name!(), &test_users)); + let ts = TestScenario::new(util_name!()); + let result = ts.ucmd().args(&test_users).run(); + let exp_result = unwrap_or_return!(expected_result(&ts, &test_users)); result .stdout_is(exp_result.stdout_str()) diff --git a/tests/by-util/test_id.rs b/tests/by-util/test_id.rs index e491236d8..e62f105de 100644 --- a/tests/by-util/test_id.rs +++ b/tests/by-util/test_id.rs @@ -12,13 +12,17 @@ const VERSION_MIN_MULTIPLE_USERS: &str = "8.31"; // this feature was introduced #[test] #[cfg(unix)] fn test_id_no_specified_user() { - let result = new_ucmd!().run(); - let exp_result = unwrap_or_return!(expected_result(util_name!(), &[])); + let ts = TestScenario::new(util_name!()); + let result = ts.ucmd().run(); + let exp_result = unwrap_or_return!(expected_result(&ts, &[])); let mut _exp_stdout = exp_result.stdout_str().to_string(); #[cfg(target_os = "linux")] { // NOTE: (SELinux NotImplemented) strip 'context' part from exp_stdout: + // example: + // uid=1001(runner) gid=121(docker) groups=121(docker),4(adm),101(systemd-journal) \ + // context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 if let Some(context_offset) = exp_result.stdout_str().find(" context=") { _exp_stdout.replace_range(context_offset.._exp_stdout.len() - 1, ""); } @@ -35,10 +39,9 @@ fn test_id_no_specified_user() { fn test_id_single_user() { let test_users = [&whoami()[..]]; - let scene = TestScenario::new(util_name!()); - let mut exp_result = unwrap_or_return!(expected_result(util_name!(), &test_users)); - scene - .ucmd() + let ts = TestScenario::new(util_name!()); + let mut exp_result = unwrap_or_return!(expected_result(&ts, &test_users)); + ts.ucmd() .args(&test_users) .run() .stdout_is(exp_result.stdout_str()) @@ -49,36 +52,32 @@ fn test_id_single_user() { for &opt in &["--user", "--group", "--groups"] { let mut args = vec![opt]; args.extend_from_slice(&test_users); - exp_result = unwrap_or_return!(expected_result(util_name!(), &args)); - scene - .ucmd() + exp_result = unwrap_or_return!(expected_result(&ts, &args)); + ts.ucmd() .args(&args) .run() .stdout_is(exp_result.stdout_str()) .stderr_is(exp_result.stderr_str().replace(": Invalid argument", "")) .code_is(exp_result.code()); args.push("--zero"); - exp_result = unwrap_or_return!(expected_result(util_name!(), &args)); - scene - .ucmd() + exp_result = unwrap_or_return!(expected_result(&ts, &args)); + ts.ucmd() .args(&args) .run() .stdout_is(exp_result.stdout_str()) .stderr_is(exp_result.stderr_str().replace(": Invalid argument", "")) .code_is(exp_result.code()); args.push("--name"); - exp_result = unwrap_or_return!(expected_result(util_name!(), &args)); - scene - .ucmd() + exp_result = unwrap_or_return!(expected_result(&ts, &args)); + ts.ucmd() .args(&args) .run() .stdout_is(exp_result.stdout_str()) .stderr_is(exp_result.stderr_str().replace(": Invalid argument", "")) .code_is(exp_result.code()); args.pop(); - exp_result = unwrap_or_return!(expected_result(util_name!(), &args)); - scene - .ucmd() + exp_result = unwrap_or_return!(expected_result(&ts, &args)); + ts.ucmd() .args(&args) .run() .stdout_is(exp_result.stdout_str()) @@ -91,8 +90,9 @@ fn test_id_single_user() { #[cfg(unix)] fn test_id_single_user_non_existing() { let args = &["hopefully_non_existing_username"]; - let result = new_ucmd!().args(args).run(); - let exp_result = unwrap_or_return!(expected_result(util_name!(), args)); + let ts = TestScenario::new(util_name!()); + let result = ts.ucmd().args(args).run(); + let exp_result = unwrap_or_return!(expected_result(&ts, args)); // It is unknown why on macOS (and possibly others?) `id` adds "Invalid argument". // coreutils 8.32: $ LC_ALL=C id foobar @@ -107,11 +107,11 @@ fn test_id_single_user_non_existing() { #[test] #[cfg(unix)] fn test_id_name() { - let scene = TestScenario::new(util_name!()); + let ts = TestScenario::new(util_name!()); for &opt in &["--user", "--group", "--groups"] { let args = [opt, "--name"]; - let result = scene.ucmd().args(&args).run(); - let exp_result = unwrap_or_return!(expected_result(util_name!(), &args)); + let result = ts.ucmd().args(&args).run(); + let exp_result = unwrap_or_return!(expected_result(&ts, &args)); result .stdout_is(exp_result.stdout_str()) .stderr_is(exp_result.stderr_str()) @@ -126,11 +126,11 @@ fn test_id_name() { #[test] #[cfg(unix)] fn test_id_real() { - let scene = TestScenario::new(util_name!()); + let ts = TestScenario::new(util_name!()); for &opt in &["--user", "--group", "--groups"] { let args = [opt, "--real"]; - let result = scene.ucmd().args(&args).run(); - let exp_result = unwrap_or_return!(expected_result(util_name!(), &args)); + let result = ts.ucmd().args(&args).run(); + let exp_result = unwrap_or_return!(expected_result(&ts, &args)); result .stdout_is(exp_result.stdout_str()) .stderr_is(exp_result.stderr_str()) @@ -178,10 +178,9 @@ fn test_id_multiple_users() { // Same typical users that GNU test suite is using. let test_users = ["root", "man", "postfix", "sshd", &whoami()]; - let scene = TestScenario::new(util_name!()); - let mut exp_result = unwrap_or_return!(expected_result(util_name!(), &test_users)); - scene - .ucmd() + let ts = TestScenario::new(util_name!()); + let mut exp_result = unwrap_or_return!(expected_result(&ts, &test_users)); + ts.ucmd() .args(&test_users) .run() .stdout_is(exp_result.stdout_str()) @@ -192,36 +191,32 @@ fn test_id_multiple_users() { for &opt in &["--user", "--group", "--groups"] { let mut args = vec![opt]; args.extend_from_slice(&test_users); - exp_result = unwrap_or_return!(expected_result(util_name!(), &args)); - scene - .ucmd() + exp_result = unwrap_or_return!(expected_result(&ts, &args)); + ts.ucmd() .args(&args) .run() .stdout_is(exp_result.stdout_str()) .stderr_is(exp_result.stderr_str().replace(": Invalid argument", "")) .code_is(exp_result.code()); args.push("--zero"); - exp_result = unwrap_or_return!(expected_result(util_name!(), &args)); - scene - .ucmd() + exp_result = unwrap_or_return!(expected_result(&ts, &args)); + ts.ucmd() .args(&args) .run() .stdout_is(exp_result.stdout_str()) .stderr_is(exp_result.stderr_str().replace(": Invalid argument", "")) .code_is(exp_result.code()); args.push("--name"); - exp_result = unwrap_or_return!(expected_result(util_name!(), &args)); - scene - .ucmd() + exp_result = unwrap_or_return!(expected_result(&ts, &args)); + ts.ucmd() .args(&args) .run() .stdout_is(exp_result.stdout_str()) .stderr_is(exp_result.stderr_str().replace(": Invalid argument", "")) .code_is(exp_result.code()); args.pop(); - exp_result = unwrap_or_return!(expected_result(util_name!(), &args)); - scene - .ucmd() + exp_result = unwrap_or_return!(expected_result(&ts, &args)); + ts.ucmd() .args(&args) .run() .stdout_is(exp_result.stdout_str()) @@ -251,10 +246,9 @@ fn test_id_multiple_users_non_existing() { &whoami(), ]; - let scene = TestScenario::new(util_name!()); - let mut exp_result = unwrap_or_return!(expected_result(util_name!(), &test_users)); - scene - .ucmd() + let ts = TestScenario::new(util_name!()); + let mut exp_result = unwrap_or_return!(expected_result(&ts, &test_users)); + ts.ucmd() .args(&test_users) .run() .stdout_is(exp_result.stdout_str()) @@ -265,36 +259,32 @@ fn test_id_multiple_users_non_existing() { for &opt in &["--user", "--group", "--groups"] { let mut args = vec![opt]; args.extend_from_slice(&test_users); - exp_result = unwrap_or_return!(expected_result(util_name!(), &args)); - scene - .ucmd() + exp_result = unwrap_or_return!(expected_result(&ts, &args)); + ts.ucmd() .args(&args) .run() .stdout_is(exp_result.stdout_str()) .stderr_is(exp_result.stderr_str().replace(": Invalid argument", "")) .code_is(exp_result.code()); args.push("--zero"); - exp_result = unwrap_or_return!(expected_result(util_name!(), &args)); - scene - .ucmd() + exp_result = unwrap_or_return!(expected_result(&ts, &args)); + ts.ucmd() .args(&args) .run() .stdout_is(exp_result.stdout_str()) .stderr_is(exp_result.stderr_str().replace(": Invalid argument", "")) .code_is(exp_result.code()); args.push("--name"); - exp_result = unwrap_or_return!(expected_result(util_name!(), &args)); - scene - .ucmd() + exp_result = unwrap_or_return!(expected_result(&ts, &args)); + ts.ucmd() .args(&args) .run() .stdout_is(exp_result.stdout_str()) .stderr_is(exp_result.stderr_str().replace(": Invalid argument", "")) .code_is(exp_result.code()); args.pop(); - exp_result = unwrap_or_return!(expected_result(util_name!(), &args)); - scene - .ucmd() + exp_result = unwrap_or_return!(expected_result(&ts, &args)); + ts.ucmd() .args(&args) .run() .stdout_is(exp_result.stdout_str()) @@ -306,20 +296,19 @@ fn test_id_multiple_users_non_existing() { #[test] #[cfg(unix)] fn test_id_default_format() { - let scene = TestScenario::new(util_name!()); + let ts = TestScenario::new(util_name!()); for &opt1 in &["--name", "--real"] { // id: cannot print only names or real IDs in default format let args = [opt1]; - scene - .ucmd() + ts.ucmd() .args(&args) .fails() - .stderr_only(unwrap_or_return!(expected_result(util_name!(), &args)).stderr_str()); + .stderr_only(unwrap_or_return!(expected_result(&ts, &args)).stderr_str()); for &opt2 in &["--user", "--group", "--groups"] { // u/g/G n/r let args = [opt2, opt1]; - let result = scene.ucmd().args(&args).run(); - let exp_result = unwrap_or_return!(expected_result(util_name!(), &args)); + let result = ts.ucmd().args(&args).run(); + let exp_result = unwrap_or_return!(expected_result(&ts, &args)); result .stdout_is(exp_result.stdout_str()) .stderr_is(exp_result.stderr_str()) @@ -329,38 +318,35 @@ fn test_id_default_format() { for &opt2 in &["--user", "--group", "--groups"] { // u/g/G let args = [opt2]; - scene - .ucmd() + ts.ucmd() .args(&args) .succeeds() - .stdout_only(unwrap_or_return!(expected_result(util_name!(), &args)).stdout_str()); + .stdout_only(unwrap_or_return!(expected_result(&ts, &args)).stdout_str()); } } #[test] #[cfg(unix)] fn test_id_zero() { - let scene = TestScenario::new(util_name!()); + let ts = TestScenario::new(util_name!()); for z_flag in &["-z", "--zero"] { // id: option --zero not permitted in default format - scene - .ucmd() + ts.ucmd() .args(&[z_flag]) .fails() - .stderr_only(unwrap_or_return!(expected_result(util_name!(), &[z_flag])).stderr_str()); + .stderr_only(unwrap_or_return!(expected_result(&ts, &[z_flag])).stderr_str()); for &opt1 in &["--name", "--real"] { // id: cannot print only names or real IDs in default format let args = [opt1, z_flag]; - scene - .ucmd() + ts.ucmd() .args(&args) .fails() - .stderr_only(unwrap_or_return!(expected_result(util_name!(), &args)).stderr_str()); + .stderr_only(unwrap_or_return!(expected_result(&ts, &args)).stderr_str()); for &opt2 in &["--user", "--group", "--groups"] { // u/g/G n/r z let args = [opt2, z_flag, opt1]; - let result = scene.ucmd().args(&args).run(); - let exp_result = unwrap_or_return!(expected_result(util_name!(), &args)); + let result = ts.ucmd().args(&args).run(); + let exp_result = unwrap_or_return!(expected_result(&ts, &args)); result .stdout_is(exp_result.stdout_str()) .stderr_is(exp_result.stderr_str()) @@ -370,11 +356,10 @@ fn test_id_zero() { for &opt2 in &["--user", "--group", "--groups"] { // u/g/G z let args = [opt2, z_flag]; - scene - .ucmd() + ts.ucmd() .args(&args) .succeeds() - .stdout_only(unwrap_or_return!(expected_result(util_name!(), &args)).stdout_str()); + .stdout_only(unwrap_or_return!(expected_result(&ts, &args)).stdout_str()); } } } diff --git a/tests/by-util/test_pinky.rs b/tests/by-util/test_pinky.rs index 220fd9108..5394dfde9 100644 --- a/tests/by-util/test_pinky.rs +++ b/tests/by-util/test_pinky.rs @@ -25,19 +25,16 @@ fn test_long_format() { let login = "root"; let pw: Passwd = Passwd::locate(login).unwrap(); let real_name = pw.user_info().replace("&", &pw.name().capitalize()); - new_ucmd!() - .arg("-l") - .arg(login) - .succeeds() - .stdout_is(format!( - "Login name: {:<28}In real life: {}\nDirectory: {:<29}Shell: {}\n\n", - login, - real_name, - pw.user_dir(), - pw.user_shell() - )); + let ts = TestScenario::new(util_name!()); + ts.ucmd().arg("-l").arg(login).succeeds().stdout_is(format!( + "Login name: {:<28}In real life: {}\nDirectory: {:<29}Shell: {}\n\n", + login, + real_name, + pw.user_dir(), + pw.user_shell() + )); - new_ucmd!() + ts.ucmd() .arg("-lb") .arg(login) .succeeds() @@ -51,9 +48,10 @@ fn test_long_format() { #[test] fn test_long_format_multiple_users() { let args = ["-l", "root", "root", "root"]; - let expect = unwrap_or_return!(expected_result(util_name!(), &args)); + let ts = TestScenario::new(util_name!()); + let expect = unwrap_or_return!(expected_result(&ts, &args)); - new_ucmd!() + ts.ucmd() .args(&args) .succeeds() .stdout_is(expect.stdout_str()) @@ -72,8 +70,9 @@ fn test_short_format_i() { // allow whitespace variation // * minor whitespace differences occur between platform built-in outputs; specifically, the number of trailing TABs may be variant let args = ["-i"]; - let actual = new_ucmd!().args(&args).succeeds().stdout_move_str(); - let expect = unwrap_or_return!(expected_result(util_name!(), &args)).stdout_move_str(); + let ts = TestScenario::new(util_name!()); + let actual = ts.ucmd().args(&args).succeeds().stdout_move_str(); + let expect = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str(); let v_actual: Vec<&str> = actual.split_whitespace().collect(); let v_expect: Vec<&str> = expect.split_whitespace().collect(); assert_eq!(v_actual, v_expect); @@ -85,8 +84,9 @@ fn test_short_format_q() { // allow whitespace variation // * minor whitespace differences occur between platform built-in outputs; specifically, the number of trailing TABs may be variant let args = ["-q"]; - let actual = new_ucmd!().args(&args).succeeds().stdout_move_str(); - let expect = unwrap_or_return!(expected_result(util_name!(), &args)).stdout_move_str(); + let ts = TestScenario::new(util_name!()); + let actual = ts.ucmd().args(&args).succeeds().stdout_move_str(); + let expect = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str(); let v_actual: Vec<&str> = actual.split_whitespace().collect(); let v_expect: Vec<&str> = expect.split_whitespace().collect(); assert_eq!(v_actual, v_expect); @@ -95,8 +95,9 @@ fn test_short_format_q() { #[cfg(unix)] #[test] fn test_no_flag() { - let actual = new_ucmd!().succeeds().stdout_move_str(); - let expect = unwrap_or_return!(expected_result(util_name!(), &[])).stdout_move_str(); + let ts = TestScenario::new(util_name!()); + let actual = ts.ucmd().succeeds().stdout_move_str(); + let expect = unwrap_or_return!(expected_result(&ts, &[])).stdout_move_str(); let v_actual: Vec<&str> = actual.split_whitespace().collect(); let v_expect: Vec<&str> = expect.split_whitespace().collect(); assert_eq!(v_actual, v_expect); diff --git a/tests/by-util/test_stat.rs b/tests/by-util/test_stat.rs index 2e0551ec5..7cff0d89c 100644 --- a/tests/by-util/test_stat.rs +++ b/tests/by-util/test_stat.rs @@ -114,16 +114,18 @@ const FS_FORMAT_STR: &str = "%b %c %i %l %n %s %S %t %T"; // avoid "%a %d %f" wh #[cfg(target_os = "linux")] fn test_terse_fs_format() { let args = ["-f", "-t", "/proc"]; - let expected_stdout = unwrap_or_return!(expected_result(util_name!(), &args)).stdout_move_str(); - new_ucmd!().args(&args).run().stdout_is(expected_stdout); + let ts = TestScenario::new(util_name!()); + let expected_stdout = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str(); + ts.ucmd().args(&args).run().stdout_is(expected_stdout); } #[test] #[cfg(target_os = "linux")] fn test_fs_format() { let args = ["-f", "-c", FS_FORMAT_STR, "/dev/shm"]; - let expected_stdout = unwrap_or_return!(expected_result(util_name!(), &args)).stdout_move_str(); - new_ucmd!().args(&args).run().stdout_is(expected_stdout); + let ts = TestScenario::new(util_name!()); + let expected_stdout = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str(); + ts.ucmd().args(&args).run().stdout_is(expected_stdout); } #[cfg(unix)] @@ -132,8 +134,9 @@ fn test_terse_normal_format() { // note: contains birth/creation date which increases test fragility // * results may vary due to built-in `stat` limitations as well as linux kernel and rust version capability variations let args = ["-t", "/"]; - let actual = new_ucmd!().args(&args).succeeds().stdout_move_str(); - let expect = unwrap_or_return!(expected_result(util_name!(), &args)).stdout_move_str(); + let ts = TestScenario::new(util_name!()); + let actual = ts.ucmd().args(&args).succeeds().stdout_move_str(); + let expect = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str(); println!("actual: {:?}", actual); println!("expect: {:?}", expect); let v_actual: Vec<&str> = actual.trim().split(' ').collect(); @@ -161,8 +164,9 @@ fn test_terse_normal_format() { #[test] fn test_format_created_time() { let args = ["-c", "%w", "/bin"]; - let actual = new_ucmd!().args(&args).succeeds().stdout_move_str(); - let expect = unwrap_or_return!(expected_result(util_name!(), &args)).stdout_move_str(); + let ts = TestScenario::new(util_name!()); + let actual = ts.ucmd().args(&args).succeeds().stdout_move_str(); + let expect = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str(); println!("actual: {:?}", actual); println!("expect: {:?}", expect); // note: using a regex instead of `split_whitespace()` in order to detect whitespace differences @@ -185,8 +189,9 @@ fn test_format_created_time() { #[test] fn test_format_created_seconds() { let args = ["-c", "%W", "/bin"]; - let actual = new_ucmd!().args(&args).succeeds().stdout_move_str(); - let expect = unwrap_or_return!(expected_result(util_name!(), &args)).stdout_move_str(); + let ts = TestScenario::new(util_name!()); + let actual = ts.ucmd().args(&args).succeeds().stdout_move_str(); + let expect = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str(); println!("actual: {:?}", actual); println!("expect: {:?}", expect); // note: using a regex instead of `split_whitespace()` in order to detect whitespace differences @@ -209,18 +214,16 @@ fn test_format_created_seconds() { #[test] fn test_normal_format() { let args = ["-c", NORMAL_FORMAT_STR, "/bin"]; - let expected_stdout = unwrap_or_return!(expected_result(util_name!(), &args)).stdout_move_str(); - new_ucmd!() - .args(&args) - .succeeds() - .stdout_is(expected_stdout); + let ts = TestScenario::new(util_name!()); + let expected_stdout = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str(); + ts.ucmd().args(&args).succeeds().stdout_is(expected_stdout); } #[cfg(unix)] #[test] fn test_symlinks() { - let scene = TestScenario::new(util_name!()); - let at = &scene.fixtures; + let ts = TestScenario::new(util_name!()); + let at = &ts.fixtures; let mut tested: bool = false; // arbitrarily chosen symlinks with hope that the CI environment provides at least one of them @@ -234,22 +237,12 @@ fn test_symlinks() { if at.file_exists(file) && at.is_symlink(file) { tested = true; let args = ["-c", NORMAL_FORMAT_STR, file]; - let expected_stdout = - unwrap_or_return!(expected_result(util_name!(), &args)).stdout_move_str(); - scene - .ucmd() - .args(&args) - .succeeds() - .stdout_is(expected_stdout); + let expected_stdout = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str(); + ts.ucmd().args(&args).succeeds().stdout_is(expected_stdout); // -L, --dereference follow links let args = ["-L", "-c", NORMAL_FORMAT_STR, file]; - let expected_stdout = - unwrap_or_return!(expected_result(util_name!(), &args)).stdout_move_str(); - scene - .ucmd() - .args(&args) - .succeeds() - .stdout_is(expected_stdout); + let expected_stdout = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str(); + ts.ucmd().args(&args).succeeds().stdout_is(expected_stdout); } } if !tested { @@ -275,11 +268,9 @@ fn test_char() { #[cfg(any(target_vendor = "apple"))] "/dev/ptmx", ]; - let expected_stdout = unwrap_or_return!(expected_result(util_name!(), &args)).stdout_move_str(); - new_ucmd!() - .args(&args) - .succeeds() - .stdout_is(expected_stdout); + let ts = TestScenario::new(util_name!()); + let expected_stdout = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str(); + ts.ucmd().args(&args).succeeds().stdout_is(expected_stdout); } #[cfg(unix)] @@ -294,11 +285,9 @@ fn test_multi_files() { "/etc/fstab", "/var", ]; - let expected_stdout = unwrap_or_return!(expected_result(util_name!(), &args)).stdout_move_str(); - new_ucmd!() - .args(&args) - .succeeds() - .stdout_is(expected_stdout); + let ts = TestScenario::new(util_name!()); + let expected_stdout = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str(); + ts.ucmd().args(&args).succeeds().stdout_is(expected_stdout); } #[cfg(unix)] @@ -308,9 +297,7 @@ fn test_printf() { "--printf=123%-# 15q\\r\\\"\\\\\\a\\b\\e\\f\\v%+020.23m\\x12\\167\\132\\112\\n", "/", ]; - let expected_stdout = unwrap_or_return!(expected_result(util_name!(), &args)).stdout_move_str(); - new_ucmd!() - .args(&args) - .succeeds() - .stdout_is(expected_stdout); + let ts = TestScenario::new(util_name!()); + let expected_stdout = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str(); + ts.ucmd().args(&args).succeeds().stdout_is(expected_stdout); } diff --git a/tests/by-util/test_who.rs b/tests/by-util/test_who.rs index c84ad0f2f..d05715517 100644 --- a/tests/by-util/test_who.rs +++ b/tests/by-util/test_who.rs @@ -10,32 +10,33 @@ use crate::common::util::*; #[cfg(unix)] #[test] fn test_count() { + let ts = TestScenario::new(util_name!()); for opt in &["-q", "--count"] { - let expected_stdout = - unwrap_or_return!(expected_result(util_name!(), &[opt])).stdout_move_str(); - new_ucmd!().arg(opt).succeeds().stdout_is(expected_stdout); + let expected_stdout = unwrap_or_return!(expected_result(&ts, &[opt])).stdout_move_str(); + ts.ucmd().arg(opt).succeeds().stdout_is(expected_stdout); } } #[cfg(unix)] #[test] fn test_boot() { + let ts = TestScenario::new(util_name!()); for opt in &["-b", "--boot"] { - let expected_stdout = - unwrap_or_return!(expected_result(util_name!(), &[opt])).stdout_move_str(); - new_ucmd!().arg(opt).succeeds().stdout_is(expected_stdout); + let expected_stdout = unwrap_or_return!(expected_result(&ts, &[opt])).stdout_move_str(); + ts.ucmd().arg(opt).succeeds().stdout_is(expected_stdout); } } #[cfg(unix)] #[test] fn test_heading() { + let ts = TestScenario::new(util_name!()); for opt in &["-H", "--heading"] { // allow whitespace variation // * minor whitespace differences occur between platform built-in outputs; // specifically number of TABs between "TIME" and "COMMENT" may be variant - let actual = new_ucmd!().arg(opt).succeeds().stdout_move_str(); - let expect = unwrap_or_return!(expected_result(util_name!(), &[opt])).stdout_move_str(); + let actual = ts.ucmd().arg(opt).succeeds().stdout_move_str(); + let expect = unwrap_or_return!(expected_result(&ts, &[opt])).stdout_move_str(); println!("actual: {:?}", actual); println!("expect: {:?}", expect); let v_actual: Vec<&str> = actual.split_whitespace().collect(); @@ -47,63 +48,63 @@ fn test_heading() { #[cfg(unix)] #[test] fn test_short() { + let ts = TestScenario::new(util_name!()); for opt in &["-s", "--short"] { - let expected_stdout = - unwrap_or_return!(expected_result(util_name!(), &[opt])).stdout_move_str(); - new_ucmd!().arg(opt).succeeds().stdout_is(expected_stdout); + let expected_stdout = unwrap_or_return!(expected_result(&ts, &[opt])).stdout_move_str(); + ts.ucmd().arg(opt).succeeds().stdout_is(expected_stdout); } } #[cfg(unix)] #[test] fn test_login() { + let ts = TestScenario::new(util_name!()); for opt in &["-l", "--login"] { - let expected_stdout = - unwrap_or_return!(expected_result(util_name!(), &[opt])).stdout_move_str(); - new_ucmd!().arg(opt).succeeds().stdout_is(expected_stdout); + let expected_stdout = unwrap_or_return!(expected_result(&ts, &[opt])).stdout_move_str(); + ts.ucmd().arg(opt).succeeds().stdout_is(expected_stdout); } } #[cfg(unix)] #[test] fn test_m() { + let ts = TestScenario::new(util_name!()); for opt in &["-m"] { - let expected_stdout = - unwrap_or_return!(expected_result(util_name!(), &[opt])).stdout_move_str(); - new_ucmd!().arg(opt).succeeds().stdout_is(expected_stdout); + let expected_stdout = unwrap_or_return!(expected_result(&ts, &[opt])).stdout_move_str(); + ts.ucmd().arg(opt).succeeds().stdout_is(expected_stdout); } } #[cfg(unix)] #[test] fn test_process() { + let ts = TestScenario::new(util_name!()); for opt in &["-p", "--process"] { - let expected_stdout = - unwrap_or_return!(expected_result(util_name!(), &[opt])).stdout_move_str(); - new_ucmd!().arg(opt).succeeds().stdout_is(expected_stdout); + let expected_stdout = unwrap_or_return!(expected_result(&ts, &[opt])).stdout_move_str(); + ts.ucmd().arg(opt).succeeds().stdout_is(expected_stdout); } } #[cfg(unix)] #[test] fn test_runlevel() { + let ts = TestScenario::new(util_name!()); for opt in &["-r", "--runlevel"] { - let expected_stdout = - unwrap_or_return!(expected_result(util_name!(), &[opt])).stdout_move_str(); - new_ucmd!().arg(opt).succeeds().stdout_is(expected_stdout); + let expected_stdout = unwrap_or_return!(expected_result(&ts, &[opt])).stdout_move_str(); + ts.ucmd().arg(opt).succeeds().stdout_is(expected_stdout); #[cfg(not(target_os = "linux"))] - new_ucmd!().arg(opt).succeeds().stdout_is(""); + ts.ucmd().arg(opt).succeeds().stdout_is(""); } } #[cfg(unix)] #[test] fn test_time() { + let ts = TestScenario::new(util_name!()); for opt in &["-t", "--time"] { - let expected_stdout = - unwrap_or_return!(expected_result(util_name!(), &[opt])).stdout_move_str(); - new_ucmd!().arg(opt).succeeds().stdout_is(expected_stdout); + let expected_stdout = unwrap_or_return!(expected_result(&ts, &[opt])).stdout_move_str(); + ts.ucmd().arg(opt).succeeds().stdout_is(expected_stdout); } } @@ -116,10 +117,10 @@ fn test_mesg() { // same as -T // --writable // same as -T + let ts = TestScenario::new(util_name!()); for opt in &["-T", "-w", "--mesg", "--message", "--writable"] { - let expected_stdout = - unwrap_or_return!(expected_result(util_name!(), &[opt])).stdout_move_str(); - new_ucmd!().arg(opt).succeeds().stdout_is(expected_stdout); + let expected_stdout = unwrap_or_return!(expected_result(&ts, &[opt])).stdout_move_str(); + ts.ucmd().arg(opt).succeeds().stdout_is(expected_stdout); } } @@ -127,12 +128,9 @@ fn test_mesg() { #[test] fn test_arg1_arg2() { let args = ["am", "i"]; - let expected_stdout = unwrap_or_return!(expected_result(util_name!(), &args)).stdout_move_str(); - - new_ucmd!() - .args(&args) - .succeeds() - .stdout_is(expected_stdout); + let ts = TestScenario::new(util_name!()); + let expected_stdout = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str(); + ts.ucmd().args(&args).succeeds().stdout_is(expected_stdout); } #[test] @@ -147,9 +145,10 @@ fn test_too_many_args() { #[cfg(unix)] #[test] fn test_users() { + let ts = TestScenario::new(util_name!()); for opt in &["-u", "--users"] { - let actual = new_ucmd!().arg(opt).succeeds().stdout_move_str(); - let expect = unwrap_or_return!(expected_result(util_name!(), &[opt])).stdout_move_str(); + let actual = ts.ucmd().arg(opt).succeeds().stdout_move_str(); + let expect = unwrap_or_return!(expected_result(&ts, &[opt])).stdout_move_str(); println!("actual: {:?}", actual); println!("expect: {:?}", expect); @@ -172,18 +171,18 @@ fn test_users() { #[test] fn test_lookup() { let opt = "--lookup"; - let expected_stdout = - unwrap_or_return!(expected_result(util_name!(), &[opt])).stdout_move_str(); - new_ucmd!().arg(opt).succeeds().stdout_is(expected_stdout); + let ts = TestScenario::new(util_name!()); + let expected_stdout = unwrap_or_return!(expected_result(&ts, &[opt])).stdout_move_str(); + ts.ucmd().arg(opt).succeeds().stdout_is(expected_stdout); } #[cfg(unix)] #[test] fn test_dead() { + let ts = TestScenario::new(util_name!()); for opt in &["-d", "--dead"] { - let expected_stdout = - unwrap_or_return!(expected_result(util_name!(), &[opt])).stdout_move_str(); - new_ucmd!().arg(opt).succeeds().stdout_is(expected_stdout); + let expected_stdout = unwrap_or_return!(expected_result(&ts, &[opt])).stdout_move_str(); + ts.ucmd().arg(opt).succeeds().stdout_is(expected_stdout); } } @@ -197,20 +196,11 @@ fn test_all_separately() { // -a, --all same as -b -d --login -p -r -t -T -u let args = ["-b", "-d", "--login", "-p", "-r", "-t", "-T", "-u"]; - let expected_stdout = unwrap_or_return!(expected_result(util_name!(), &args)).stdout_move_str(); - let scene = TestScenario::new(util_name!()); - scene - .ucmd() - .args(&args) - .succeeds() - .stdout_is(expected_stdout); - let expected_stdout = - unwrap_or_return!(expected_result(util_name!(), &["--all"])).stdout_move_str(); - scene - .ucmd() - .arg("--all") - .succeeds() - .stdout_is(expected_stdout); + let ts = TestScenario::new(util_name!()); + let expected_stdout = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str(); + ts.ucmd().args(&args).succeeds().stdout_is(expected_stdout); + let expected_stdout = unwrap_or_return!(expected_result(&ts, &["--all"])).stdout_move_str(); + ts.ucmd().arg("--all").succeeds().stdout_is(expected_stdout); } #[cfg(unix)] @@ -221,9 +211,9 @@ fn test_all() { return; } + let ts = TestScenario::new(util_name!()); for opt in &["-a", "--all"] { - let expected_stdout = - unwrap_or_return!(expected_result(util_name!(), &[opt])).stdout_move_str(); - new_ucmd!().arg(opt).succeeds().stdout_is(expected_stdout); + let expected_stdout = unwrap_or_return!(expected_result(&ts, &[opt])).stdout_move_str(); + ts.ucmd().arg(opt).succeeds().stdout_is(expected_stdout); } } diff --git a/tests/common/util.rs b/tests/common/util.rs index 2cff46224..acffaca13 100644 --- a/tests/common/util.rs +++ b/tests/common/util.rs @@ -701,7 +701,7 @@ impl AtPath { /// Fixtures can be found under `tests/fixtures/$util_name/` pub struct TestScenario { bin_path: PathBuf, - util_name: String, + pub util_name: String, pub fixtures: AtPath, tmpd: Rc, } @@ -1171,8 +1171,9 @@ pub fn check_coreutil_version( /// use crate::common::util::*; /// #[test] /// fn test_xyz() { -/// let result = new_ucmd!().run(); -/// let exp_result = unwrap_or_return!(expected_result(util_name!(), &[])); +/// let ts = TestScenario::new(util_name!()); +/// let result = ts.ucmd().run(); +/// let exp_result = unwrap_or_return!(expected_result(&ts, &[])); /// result /// .stdout_is(exp_result.stdout_str()) /// .stderr_is(exp_result.stderr_str()) @@ -1180,12 +1181,11 @@ pub fn check_coreutil_version( /// } ///``` #[cfg(unix)] -pub fn expected_result(util_name: &str, args: &[&str]) -> std::result::Result { - let util_name = &host_name_for(util_name); +pub fn expected_result(ts: &TestScenario, args: &[&str]) -> std::result::Result { + let util_name = &host_name_for(&ts.util_name); println!("{}", check_coreutil_version(util_name, VERSION_MIN)?); - let scene = TestScenario::new(util_name); - let result = scene + let result = ts .cmd_keepenv(util_name.as_ref()) .env("LC_ALL", "C") .args(args) @@ -1470,7 +1470,9 @@ mod tests { #[test] #[cfg(unix)] fn test_expected_result() { - assert!(expected_result("id", &[]).is_ok()); - assert!(expected_result("no test name", &[]).is_err()); + let ts = TestScenario::new("id"); + assert!(expected_result(&ts, &[]).is_ok()); + let ts = TestScenario::new("no test name"); + assert!(expected_result(&ts, &[]).is_err()); } } From d57f474ae1c5d33b2482a28d7663cced0f0958ac Mon Sep 17 00:00:00 2001 From: Jan Scheer Date: Thu, 8 Jul 2021 00:21:28 +0200 Subject: [PATCH 24/25] test_whoami: refactor use expected_result and whoami from common/util.rs --- tests/by-util/test_whoami.rs | 86 ++++++++++++++---------------------- 1 file changed, 34 insertions(+), 52 deletions(-) diff --git a/tests/by-util/test_whoami.rs b/tests/by-util/test_whoami.rs index a98541b2d..cba941558 100644 --- a/tests/by-util/test_whoami.rs +++ b/tests/by-util/test_whoami.rs @@ -1,63 +1,45 @@ +// * This file is part of the uutils coreutils package. +// * +// * For the full copyright and license information, please view the LICENSE +// * file that was distributed with this source code. + use crate::common::util::*; -// Apparently some CI environments have configuration issues, e.g. with 'whoami' and 'id'. -// If we are running inside the CI and "needle" is in "stderr" skipping this test is -// considered okay. If we are not inside the CI this calls assert!(result.success). -// -// From the Logs: "Build (ubuntu-18.04, x86_64-unknown-linux-gnu, feat_os_unix, use-cross)" -// stderr: "whoami: failed to get username" -// Maybe: "adduser --uid 1001 username" can put things right? -fn skipping_test_is_okay(result: &CmdResult, needle: &str) -> bool { - if !result.succeeded() { - println!("result.stdout = {}", result.stdout_str()); - println!("result.stderr = {}", result.stderr_str()); - if is_ci() && result.stderr_str().contains(needle) { - println!("test skipped:"); - return true; - } else { - result.success(); - } - } - false -} - #[test] +#[cfg(unix)] fn test_normal() { - let (_, mut ucmd) = at_and_ucmd!(); + let ts = TestScenario::new(util_name!()); + let result = ts.ucmd().run(); + let exp_result = unwrap_or_return!(expected_result(&ts, &[])); - let result = ucmd.run(); - - // use std::env; - // println!("env::var(CI).is_ok() = {}", env::var("CI").is_ok()); - // for (key, value) in env::vars() { - // println!("{}: {}", key, value); - // } - - if skipping_test_is_okay(&result, "failed to get username") { - return; - } - - result.no_stderr(); - assert!(!result.stdout_str().trim().is_empty()); + result + .stdout_is(exp_result.stdout_str()) + .stderr_is(exp_result.stderr_str()) + .code_is(exp_result.code()); } #[test] -#[cfg(not(windows))] +#[cfg(unix)] fn test_normal_compare_id() { - let scene = TestScenario::new(util_name!()); - - let result_ucmd = scene.ucmd().run(); - if skipping_test_is_okay(&result_ucmd, "failed to get username") { - return; + let ts = TestScenario::new("id"); + let id_un = unwrap_or_return!(expected_result(&ts, &["-un"])); + if id_un.succeeded() { + new_ucmd!().succeeds().stdout_is(id_un.stdout_str()); + } else if is_ci() && id_un.stderr_str().contains("cannot find name for user ID") { + println!("test skipped:"); + } else { + id_un.success(); + } +} + +#[test] +#[cfg(unix)] +fn test_normal_compare_env() { + let whoami = whoami(); + if whoami == "nobody" { + println!("test skipped:"); + return; + } else { + new_ucmd!().succeeds().stdout_is(format!("{}\n", whoami)); } - - let result_cmd = scene.cmd("id").arg("-un").run(); - if skipping_test_is_okay(&result_cmd, "cannot find name for user ID") { - return; - } - - assert_eq!( - result_ucmd.stdout_str().trim(), - result_cmd.stdout_str().trim() - ); } From 14b348dd4b4c467ad44426852c4a4d270553f092 Mon Sep 17 00:00:00 2001 From: Jan Scheer Date: Thu, 8 Jul 2021 01:32:39 +0200 Subject: [PATCH 25/25] tests: fix tests for CICD environment --- tests/by-util/test_du.rs | 3 +-- tests/by-util/test_groups.rs | 2 ++ tests/by-util/test_whoami.rs | 5 ++++- tests/common/util.rs | 12 +++++++++--- 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/tests/by-util/test_du.rs b/tests/by-util/test_du.rs index 607d5dc45..e63aa4585 100644 --- a/tests/by-util/test_du.rs +++ b/tests/by-util/test_du.rs @@ -573,8 +573,7 @@ fn test_du_bytes() { #[cfg(all( not(target_vendor = "apple"), not(target_os = "windows"), - not(target_os = "freebsd"), - not(target_os = "linux") + not(target_os = "freebsd") ))] result.stdout_contains("21529\t./subdir\n"); } diff --git a/tests/by-util/test_groups.rs b/tests/by-util/test_groups.rs index 14e5a356d..73837235f 100644 --- a/tests/by-util/test_groups.rs +++ b/tests/by-util/test_groups.rs @@ -3,6 +3,8 @@ // * For the full copyright and license information, please view the LICENSE // * file that was distributed with this source code. +//spell-checker: ignore coreutil + use crate::common::util::*; const VERSION_MIN_MULTIPLE_USERS: &str = "8.31"; // this feature was introduced in GNU's coreutils 8.31 diff --git a/tests/by-util/test_whoami.rs b/tests/by-util/test_whoami.rs index cba941558..0afe94161 100644 --- a/tests/by-util/test_whoami.rs +++ b/tests/by-util/test_whoami.rs @@ -3,6 +3,7 @@ // * For the full copyright and license information, please view the LICENSE // * file that was distributed with this source code. +#[cfg(unix)] use crate::common::util::*; #[test] @@ -39,7 +40,9 @@ fn test_normal_compare_env() { if whoami == "nobody" { println!("test skipped:"); return; - } else { + } else if !is_ci() { new_ucmd!().succeeds().stdout_is(format!("{}\n", whoami)); + } else { + println!("test skipped:"); } } diff --git a/tests/common/util.rs b/tests/common/util.rs index acffaca13..7a641a353 100644 --- a/tests/common/util.rs +++ b/tests/common/util.rs @@ -10,6 +10,7 @@ use pretty_assertions::assert_eq; #[cfg(target_os = "linux")] use rlimit::{prlimit, rlim}; +#[cfg(unix)] use std::borrow::Cow; use std::env; #[cfg(not(windows))] @@ -1456,9 +1457,10 @@ mod tests { #[cfg(unix)] fn test_check_coreutil_version() { match check_coreutil_version("id", VERSION_MIN) { - Ok(s) => s.starts_with("uutils-tests-"), - Err(s) => s.starts_with("uutils-tests-warning"), + Ok(s) => assert!(s.starts_with("uutils-tests-")), + Err(s) => assert!(s.starts_with("uutils-tests-warning")), }; + #[cfg(target_os = "linux")] std::assert_eq!( check_coreutil_version("no test name", VERSION_MIN), Err("uutils-tests-warning: 'no test name' \ @@ -1471,7 +1473,11 @@ mod tests { #[cfg(unix)] fn test_expected_result() { let ts = TestScenario::new("id"); - assert!(expected_result(&ts, &[]).is_ok()); + // assert!(expected_result(&ts, &[]).is_ok()); + match expected_result(&ts, &[]) { + Ok(r) => assert!(r.succeeded()), + Err(s) => assert!(s.starts_with("uutils-tests-warning")), + } let ts = TestScenario::new("no test name"); assert!(expected_result(&ts, &[]).is_err()); }