1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-09-16 19:56:17 +00:00

Merge branch 'master' into tail_notify

This commit is contained in:
Jan Scheer 2021-10-26 16:33:20 +02:00
commit 63e9cd9202
No known key found for this signature in database
GPG key ID: C62AD4C29E2B9828
173 changed files with 1787 additions and 1213 deletions

View file

@ -113,12 +113,18 @@ fn test_wrap_bad_arg() {
#[test]
fn test_base32_extra_operand() {
let ts = TestScenario::new(util_name!());
// Expect a failure when multiple files are specified.
new_ucmd!()
ts.ucmd()
.arg("a.txt")
.arg("b.txt")
.fails()
.stderr_only("base32: extra operand 'b.txt'\nTry 'base32 --help' for more information.");
.stderr_only(format!(
"{0}: extra operand 'b.txt'\nTry '{1} {0} --help' for more information.",
ts.util_name,
ts.bin_path.to_string_lossy()
));
}
#[test]

View file

@ -95,12 +95,18 @@ fn test_wrap_bad_arg() {
#[test]
fn test_base64_extra_operand() {
let ts = TestScenario::new(util_name!());
// Expect a failure when multiple files are specified.
new_ucmd!()
ts.ucmd()
.arg("a.txt")
.arg("b.txt")
.fails()
.stderr_only("base64: extra operand 'b.txt'\nTry 'base64 --help' for more information.");
.stderr_only(format!(
"{0}: extra operand 'b.txt'\nTry '{1} {0} --help' for more information.",
ts.util_name,
ts.bin_path.to_string_lossy()
));
}
#[test]

View file

@ -4,7 +4,7 @@ use std::os::unix::fs::{OpenOptionsExt, PermissionsExt};
use std::sync::Mutex;
extern crate libc;
use self::chmod::strip_minus_from_mode;
use uucore::mode::strip_minus_from_mode;
extern crate chmod;
use self::libc::umask;

View file

@ -15,6 +15,7 @@ fn test_missing_operand() {
#[test]
fn test_enter_chroot_fails() {
// NOTE: since #2689 this test also ensures that we don't regress #2687
let (at, mut ucmd) = at_and_ucmd!();
at.mkdir("jail");
@ -89,3 +90,26 @@ fn test_preference_of_userspec() {
println!("result.stdout = {}", result.stdout_str());
println!("result.stderr = {}", result.stderr_str());
}
#[test]
fn test_default_shell() {
// NOTE: This test intends to trigger code which can only be reached with root permissions.
let ts = TestScenario::new(util_name!());
let at = &ts.fixtures;
let dir = "CHROOT_DIR";
at.mkdir(dir);
let shell = std::env::var("SHELL").unwrap_or_else(|_| "/bin/sh".to_string());
let _expected = format!(
"chroot: failed to run command '{}': No such file or directory",
shell
);
// TODO: [2021-09; jhscheer] uncomment if/when #2692 gets merged
// if let Ok(result) = run_ucmd_as_root(&ts, &[dir]) {
// result.stderr_contains(expected);
// } else {
// print!("TEST SKIPPED");
// }
}

View file

@ -28,9 +28,7 @@ macro_rules! fixture_path {
macro_rules! assert_fixture_exists {
($fname:expr) => {{
let fpath = fixture_path!($fname);
if !fpath.exists() {
panic!("Fixture missing: {:?}", fpath);
}
assert!(fpath.exists(), "Fixture missing: {:?}", fpath);
}};
}
@ -38,9 +36,7 @@ macro_rules! assert_fixture_exists {
macro_rules! assert_fixture_not_exists {
($fname:expr) => {{
let fpath = PathBuf::from(format!("./fixtures/dd/{}", $fname));
if fpath.exists() {
panic!("Fixture present: {:?}", fpath);
}
assert!(!fpath.exists(), "Fixture present: {:?}", fpath);
}};
}

View file

@ -347,6 +347,7 @@ fn test_ls_long_format() {
// A line of the output should be:
// One of the characters -bcCdDlMnpPsStTx?
// rwx, with - for missing permissions, thrice.
// Zero or one "." for indicating a file with security context
// A number, preceded by column whitespace, and followed by a single space.
// A username, currently [^ ], followed by column whitespace, twice (or thrice for Hurd).
// A number, followed by a single space.
@ -356,13 +357,13 @@ fn test_ls_long_format() {
// and followed by a single space.
// Whatever comes after is irrelevant to this specific test.
scene.ucmd().arg(arg).arg("test-long-dir").succeeds().stdout_matches(&Regex::new(
r"\n[-bcCdDlMnpPsStTx?]([r-][w-][xt-]){3} +\d+ [^ ]+ +[^ ]+( +[^ ]+)? +\d+ [A-Z][a-z]{2} {0,2}\d{0,2} {0,2}[0-9:]+ "
r"\n[-bcCdDlMnpPsStTx?]([r-][w-][xt-]){3}\.? +\d+ [^ ]+ +[^ ]+( +[^ ]+)? +\d+ [A-Z][a-z]{2} {0,2}\d{0,2} {0,2}[0-9:]+ "
).unwrap());
}
// This checks for the line with the .. entry. The uname and group should be digits.
scene.ucmd().arg("-lan").arg("test-long-dir").succeeds().stdout_matches(&Regex::new(
r"\nd([r-][w-][xt-]){3} +\d+ \d+ +\d+( +\d+)? +\d+ [A-Z][a-z]{2} {0,2}\d{0,2} {0,2}[0-9:]+ \.\."
r"\nd([r-][w-][xt-]){3}\.? +\d+ \d+ +\d+( +\d+)? +\d+ [A-Z][a-z]{2} {0,2}\d{0,2} {0,2}[0-9:]+ \.\."
).unwrap());
}
@ -370,6 +371,7 @@ fn test_ls_long_format() {
/// This test is mainly about coloring, but, the recursion, symlink `->` processing,
/// and `.` and `..` being present in `-a` all need to work for the test to pass.
/// This test does not really test anything provided by `-l` but the file names and symlinks.
#[cfg(all(feature = "ln", feature = "mkdir", feature = "touch"))]
#[test]
#[cfg(all(feature = "ln", feature = "mkdir", feature = "touch"))]
fn test_ls_long_symlink_color() {
@ -636,55 +638,57 @@ fn test_ls_long_formats() {
let at = &scene.fixtures;
at.touch(&at.plus_as_string("test-long-formats"));
// Zero or one "." for indicating a file with security context
// Regex for three names, so all of author, group and owner
let re_three = Regex::new(r"[xrw-]{9} \d ([-0-9_a-z]+ ){3}0").unwrap();
let re_three = Regex::new(r"[xrw-]{9}\.? \d ([-0-9_a-z]+ ){3}0").unwrap();
#[cfg(unix)]
let re_three_num = Regex::new(r"[xrw-]{9} \d (\d+ ){3}0").unwrap();
let re_three_num = Regex::new(r"[xrw-]{9}\.? \d (\d+ ){3}0").unwrap();
// Regex for two names, either:
// - group and owner
// - author and owner
// - author and group
let re_two = Regex::new(r"[xrw-]{9} \d ([-0-9_a-z]+ ){2}0").unwrap();
let re_two = Regex::new(r"[xrw-]{9}\.? \d ([-0-9_a-z]+ ){2}0").unwrap();
#[cfg(unix)]
let re_two_num = Regex::new(r"[xrw-]{9} \d (\d+ ){2}0").unwrap();
let re_two_num = Regex::new(r"[xrw-]{9}\.? \d (\d+ ){2}0").unwrap();
// Regex for one name: author, group or owner
let re_one = Regex::new(r"[xrw-]{9} \d [-0-9_a-z]+ 0").unwrap();
let re_one = Regex::new(r"[xrw-]{9}\.? \d [-0-9_a-z]+ 0").unwrap();
#[cfg(unix)]
let re_one_num = Regex::new(r"[xrw-]{9} \d \d+ 0").unwrap();
let re_one_num = Regex::new(r"[xrw-]{9}\.? \d \d+ 0").unwrap();
// Regex for no names
let re_zero = Regex::new(r"[xrw-]{9} \d 0").unwrap();
let re_zero = Regex::new(r"[xrw-]{9}\.? \d 0").unwrap();
let result = scene
scene
.ucmd()
.arg("-l")
.arg("--author")
.arg("test-long-formats")
.succeeds();
assert!(re_three.is_match(result.stdout_str()));
.succeeds()
.stdout_matches(&re_three);
let result = scene
scene
.ucmd()
.arg("-l1")
.arg("--author")
.arg("test-long-formats")
.succeeds();
assert!(re_three.is_match(result.stdout_str()));
.succeeds()
.stdout_matches(&re_three);
#[cfg(unix)]
{
let result = scene
scene
.ucmd()
.arg("-n")
.arg("--author")
.arg("test-long-formats")
.succeeds();
assert!(re_three_num.is_match(result.stdout_str()));
.succeeds()
.stdout_matches(&re_three_num);
}
for arg in &[
@ -694,22 +698,22 @@ fn test_ls_long_formats() {
"-lG --author", // only author and owner
"-l --no-group --author", // only author and owner
] {
let result = scene
scene
.ucmd()
.args(&arg.split(' ').collect::<Vec<_>>())
.arg("test-long-formats")
.succeeds();
assert!(re_two.is_match(result.stdout_str()));
.succeeds()
.stdout_matches(&re_two);
#[cfg(unix)]
{
let result = scene
scene
.ucmd()
.arg("-n")
.args(&arg.split(' ').collect::<Vec<_>>())
.arg("test-long-formats")
.succeeds();
assert!(re_two_num.is_match(result.stdout_str()));
.succeeds()
.stdout_matches(&re_two_num);
}
}
@ -723,22 +727,22 @@ fn test_ls_long_formats() {
"-l --no-group", // only owner
"-gG --author", // only author
] {
let result = scene
scene
.ucmd()
.args(&arg.split(' ').collect::<Vec<_>>())
.arg("test-long-formats")
.succeeds();
assert!(re_one.is_match(result.stdout_str()));
.succeeds()
.stdout_matches(&re_one);
#[cfg(unix)]
{
let result = scene
scene
.ucmd()
.arg("-n")
.args(&arg.split(' ').collect::<Vec<_>>())
.arg("test-long-formats")
.succeeds();
assert!(re_one_num.is_match(result.stdout_str()));
.succeeds()
.stdout_matches(&re_one_num);
}
}
@ -755,22 +759,22 @@ fn test_ls_long_formats() {
"-og1",
"-og1l",
] {
let result = scene
scene
.ucmd()
.args(&arg.split(' ').collect::<Vec<_>>())
.arg("test-long-formats")
.succeeds();
assert!(re_zero.is_match(result.stdout_str()));
.succeeds()
.stdout_matches(&re_zero);
#[cfg(unix)]
{
let result = scene
scene
.ucmd()
.arg("-n")
.args(&arg.split(' ').collect::<Vec<_>>())
.arg("test-long-formats")
.succeeds();
assert!(re_zero.is_match(result.stdout_str()));
.succeeds()
.stdout_matches(&re_zero);
}
}
}
@ -1248,7 +1252,7 @@ fn test_ls_inode() {
at.touch(file);
let re_short = Regex::new(r" *(\d+) test_inode").unwrap();
let re_long = Regex::new(r" *(\d+) [xrw-]{10} \d .+ test_inode").unwrap();
let re_long = Regex::new(r" *(\d+) [xrw-]{10}\.? \d .+ test_inode").unwrap();
let result = scene.ucmd().arg("test_inode").arg("-i").succeeds();
assert!(re_short.is_match(result.stdout_str()));
@ -2272,3 +2276,68 @@ fn test_ls_dangling_symlinks() {
.succeeds() // this should fail, though at the moment, ls lacks a way to propagate errors encountered during display
.stdout_contains(if cfg!(windows) { "dangle" } else { "? dangle" });
}
#[test]
#[cfg(feature = "feat_selinux")]
fn test_ls_context1() {
use selinux::{self, KernelSupport};
if selinux::kernel_support() == KernelSupport::Unsupported {
println!("test skipped: Kernel has no support for SElinux context",);
return;
}
let file = "test_ls_context_file";
let expected = format!("unconfined_u:object_r:user_tmp_t:s0 {}\n", file);
let (at, mut ucmd) = at_and_ucmd!();
at.touch(file);
ucmd.args(&["-Z", file]).succeeds().stdout_is(expected);
}
#[test]
#[cfg(feature = "feat_selinux")]
fn test_ls_context2() {
use selinux::{self, KernelSupport};
if selinux::kernel_support() == KernelSupport::Unsupported {
println!("test skipped: Kernel has no support for SElinux context",);
return;
}
let ts = TestScenario::new(util_name!());
for c_flag in &["-Z", "--context"] {
ts.ucmd()
.args(&[c_flag, &"/"])
.succeeds()
.stdout_only(unwrap_or_return!(expected_result(&ts, &[c_flag, &"/"])).stdout_str());
}
}
#[test]
#[cfg(feature = "feat_selinux")]
fn test_ls_context_format() {
use selinux::{self, KernelSupport};
if selinux::kernel_support() == KernelSupport::Unsupported {
println!("test skipped: Kernel has no support for SElinux context",);
return;
}
let ts = TestScenario::new(util_name!());
// NOTE:
// --format=long/verbose matches the output of GNU's ls for --context
// except for the size count which may differ to the size count reported by GNU's ls.
for word in &[
"across",
"commas",
"horizontal",
// "long",
"single-column",
// "verbose",
"vertical",
] {
let format = format!("--format={}", word);
ts.ucmd()
.args(&[&"-Z", &format.as_str(), &"/"])
.succeeds()
.stdout_only(
unwrap_or_return!(expected_result(&ts, &[&"-Z", &format.as_str(), &"/"]))
.stdout_str(),
);
}
}

View file

@ -1,4 +1,6 @@
use crate::common::util::*;
#[cfg(not(windows))]
use std::os::unix::fs::PermissionsExt;
static TEST_DIR1: &str = "mkdir_test1";
static TEST_DIR2: &str = "mkdir_test2";
@ -65,3 +67,36 @@ fn test_mkdir_dup_file() {
// mkdir should fail for a file even if -p is specified.
scene.ucmd().arg("-p").arg(TEST_FILE7).fails();
}
#[test]
#[cfg(not(windows))]
fn test_symbolic_mode() {
let (at, mut ucmd) = at_and_ucmd!();
ucmd.arg("-m").arg("a=rwx").arg(TEST_DIR1).succeeds();
let perms = at.metadata(TEST_DIR1).permissions().mode();
assert_eq!(perms, 0o40777)
}
#[test]
#[cfg(not(windows))]
fn test_symbolic_alteration() {
let (at, mut ucmd) = at_and_ucmd!();
ucmd.arg("-m").arg("-w").arg(TEST_DIR1).succeeds();
let perms = at.metadata(TEST_DIR1).permissions().mode();
assert_eq!(perms, 0o40555)
}
#[test]
#[cfg(not(windows))]
fn test_multi_symbolic() {
let (at, mut ucmd) = at_and_ucmd!();
ucmd.arg("-m")
.arg("u=rwx,g=rx,o=")
.arg(TEST_DIR1)
.succeeds();
let perms = at.metadata(TEST_DIR1).permissions().mode();
assert_eq!(perms, 0o40750)
}

View file

@ -1,3 +1,4 @@
// spell-checker:ignore abcdefghijklmnopqrstuvwxyz
// * This file is part of the uutils coreutils package.
// *
// * For the full copyright and license information, please view the LICENSE
@ -35,9 +36,10 @@ fn test_file() {
{
let mut f = File::create(&file).unwrap();
// spell-checker:disable-next-line
if f.write_all(b"abcdefghijklmnopqrstuvwxyz\n").is_err() {
panic!("Test setup failed - could not write file");
}
assert!(
!f.write_all(b"abcdefghijklmnopqrstuvwxyz\n").is_err(),
"Test setup failed - could not write file"
);
}
new_ucmd!()
@ -75,9 +77,10 @@ fn test_2files() {
// spell-checker:disable-next-line
for &(path, data) in &[(&file1, "abcdefghijklmnop"), (&file2, "qrstuvwxyz\n")] {
let mut f = File::create(&path).unwrap();
if f.write_all(data.as_bytes()).is_err() {
panic!("Test setup failed - could not write file");
}
assert!(
!f.write_all(data.as_bytes()).is_err(),
"Test setup failed - could not write file"
);
}
new_ucmd!()
@ -126,9 +129,10 @@ fn test_from_mixed() {
let (data1, data2, data3) = ("abcdefg", "hijklmnop", "qrstuvwxyz\n");
for &(path, data) in &[(&file1, data1), (&file3, data3)] {
let mut f = File::create(&path).unwrap();
if f.write_all(data.as_bytes()).is_err() {
panic!("Test setup failed - could not write file");
}
assert!(
!f.write_all(data.as_bytes()).is_err(),
"Test setup failed - could not write file"
);
}
new_ucmd!()

View file

@ -1,6 +1,69 @@
use crate::common::util::*;
use std::io::Read;
#[test]
fn test_hex_rejects_sign_after_identifier() {
new_ucmd!()
.args(&["0x-123ABC"])
.fails()
.no_stdout()
.stderr_contains("invalid hexadecimal argument: '0x-123ABC'")
.stderr_contains("for more information.");
new_ucmd!()
.args(&["0x+123ABC"])
.fails()
.no_stdout()
.stderr_contains("invalid hexadecimal argument: '0x+123ABC'")
.stderr_contains("for more information.");
new_ucmd!()
.args(&["-0x-123ABC"])
.fails()
.no_stdout()
.stderr_contains("invalid hexadecimal argument: '-0x-123ABC'")
.stderr_contains("for more information.");
new_ucmd!()
.args(&["-0x+123ABC"])
.fails()
.no_stdout()
.stderr_contains("invalid hexadecimal argument: '-0x+123ABC'")
.stderr_contains("for more information.");
}
#[test]
fn test_hex_lowercase_uppercase() {
new_ucmd!()
.args(&["0xa", "0xA"])
.succeeds()
.stdout_is("10\n");
new_ucmd!()
.args(&["0Xa", "0XA"])
.succeeds()
.stdout_is("10\n");
}
#[test]
fn test_hex_big_number() {
new_ucmd!()
.args(&[
"0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
"0x100000000000000000000000000000000",
])
.succeeds()
.stdout_is(
"340282366920938463463374607431768211455\n340282366920938463463374607431768211456\n",
);
}
#[test]
fn test_hex_identifier_in_wrong_place() {
new_ucmd!()
.args(&["1234ABCD0x"])
.fails()
.no_stdout()
.stderr_contains("invalid hexadecimal argument: '1234ABCD0x'")
.stderr_contains("for more information.");
}
#[test]
fn test_rejects_nan() {
let ts = TestScenario::new(util_name!());

View file

@ -145,7 +145,9 @@ fn test_invalid_utf8() {
.arg("not-utf8-sequence.txt")
.run()
.failure()
.stderr_only("uniq: invalid utf-8 sequence of 1 bytes from index 0");
.stderr_only(
"uniq: failed to convert line to utf8: invalid utf-8 sequence of 1 bytes from index 0",
);
}
#[test]

View file

@ -163,25 +163,23 @@ impl CmdResult {
/// asserts that the command resulted in a success (zero) status code
pub fn success(&self) -> &CmdResult {
if !self.success {
panic!(
"Command was expected to succeed.\nstdout = {}\n stderr = {}",
self.stdout_str(),
self.stderr_str()
);
}
assert!(
self.success,
"Command was expected to succeed.\nstdout = {}\n stderr = {}",
self.stdout_str(),
self.stderr_str()
);
self
}
/// asserts that the command resulted in a failure (non-zero) status code
pub fn failure(&self) -> &CmdResult {
if self.success {
panic!(
"Command was expected to fail.\nstdout = {}\n stderr = {}",
self.stdout_str(),
self.stderr_str()
);
}
assert!(
!self.success,
"Command was expected to fail.\nstdout = {}\n stderr = {}",
self.stdout_str(),
self.stderr_str()
);
self
}
@ -197,12 +195,11 @@ impl CmdResult {
/// 1. you can not know exactly what stdout will be or
/// 2. you know that stdout will also be empty
pub fn no_stderr(&self) -> &CmdResult {
if !self.stderr.is_empty() {
panic!(
"Expected stderr to be empty, but it's:\n{}",
self.stderr_str()
);
}
assert!(
self.stderr.is_empty(),
"Expected stderr to be empty, but it's:\n{}",
self.stderr_str()
);
self
}
@ -213,12 +210,11 @@ impl CmdResult {
/// 1. you can not know exactly what stderr will be or
/// 2. you know that stderr will also be empty
pub fn no_stdout(&self) -> &CmdResult {
if !self.stdout.is_empty() {
panic!(
"Expected stdout to be empty, but it's:\n{}",
self.stderr_str()
);
}
assert!(
self.stdout.is_empty(),
"Expected stdout to be empty, but it's:\n{}",
self.stderr_str()
);
self
}
@ -514,37 +510,51 @@ impl AtPath {
}
pub fn write(&self, name: &str, contents: &str) {
log_info("open(write)", self.plus_as_string(name));
log_info("write(default)", self.plus_as_string(name));
std::fs::write(self.plus(name), contents)
.unwrap_or_else(|e| panic!("Couldn't write {}: {}", name, e));
}
pub fn write_bytes(&self, name: &str, contents: &[u8]) {
log_info("open(write)", self.plus_as_string(name));
log_info("write(default)", self.plus_as_string(name));
std::fs::write(self.plus(name), contents)
.unwrap_or_else(|e| panic!("Couldn't write {}: {}", name, e));
}
pub fn append(&self, name: &str, contents: &str) {
log_info("open(append)", self.plus_as_string(name));
log_info("write(append)", self.plus_as_string(name));
let mut f = OpenOptions::new()
.write(true)
.append(true)
.create(true)
.open(self.plus(name))
.unwrap();
f.write_all(contents.as_bytes())
.unwrap_or_else(|e| panic!("Couldn't write {}: {}", name, e));
.unwrap_or_else(|e| panic!("Couldn't write(append) {}: {}", name, e));
}
pub fn append_bytes(&self, name: &str, contents: &[u8]) {
log_info("open(append)", self.plus_as_string(name));
log_info("write(append)", self.plus_as_string(name));
let mut f = OpenOptions::new()
.write(true)
.append(true)
.create(true)
.open(self.plus(name))
.unwrap();
f.write_all(contents)
.unwrap_or_else(|e| panic!("Couldn't append to {}: {}", name, e));
.unwrap_or_else(|e| panic!("Couldn't write(append) to {}: {}", name, e));
}
pub fn truncate(&self, name: &str, contents: &str) {
log_info("write(truncate)", self.plus_as_string(name));
let mut f = OpenOptions::new()
.write(true)
.truncate(true)
.create(true)
.open(self.plus(name))
.unwrap();
f.write_all(contents.as_bytes())
.unwrap_or_else(|e| panic!("Couldn't write(truncate) {}: {}", name, e));
}
pub fn rename(&self, source: &str, target: &str) {
@ -570,10 +580,16 @@ impl AtPath {
.unwrap_or_else(|e| panic!("Couldn't copy {:?} -> {:?}: {}", source, target, e));
}
pub fn rmdir(&self, dir: &str) {
log_info("rmdir", self.plus_as_string(dir));
fs::remove_dir(&self.plus(dir)).unwrap();
}
pub fn mkdir(&self, dir: &str) {
log_info("mkdir", self.plus_as_string(dir));
fs::create_dir(&self.plus(dir)).unwrap();
}
pub fn mkdir_all(&self, dir: &str) {
log_info("mkdir_all", self.plus_as_string(dir));
fs::create_dir_all(self.plus(dir)).unwrap();
@ -891,9 +907,7 @@ impl UCommand {
/// Add a parameter to the invocation. Path arguments are treated relative
/// to the test environment directory.
pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut UCommand {
if self.has_run {
panic!("{}", ALREADY_RUN);
}
assert!(!self.has_run, "{}", ALREADY_RUN);
self.comm_string.push(' ');
self.comm_string
.push_str(arg.as_ref().to_str().unwrap_or_default());
@ -904,9 +918,7 @@ impl UCommand {
/// Add multiple parameters to the invocation. Path arguments are treated relative
/// to the test environment directory.
pub fn args<S: AsRef<OsStr>>(&mut self, args: &[S]) -> &mut UCommand {
if self.has_run {
panic!("{}", MULTIPLE_STDIN_MEANINGLESS);
}
assert!(!self.has_run, "{}", MULTIPLE_STDIN_MEANINGLESS);
let strings = args
.iter()
.map(|s| s.as_ref().to_os_string())
@ -924,9 +936,11 @@ impl UCommand {
/// provides standard input to feed in to the command when spawned
pub fn pipe_in<T: Into<Vec<u8>>>(&mut self, input: T) -> &mut UCommand {
if self.bytes_into_stdin.is_some() {
panic!("{}", MULTIPLE_STDIN_MEANINGLESS);
}
assert!(
!self.bytes_into_stdin.is_some(),
"{}",
MULTIPLE_STDIN_MEANINGLESS
);
self.bytes_into_stdin = Some(input.into());
self
}
@ -941,9 +955,7 @@ impl UCommand {
/// This is typically useful to test non-standard workflows
/// like feeding something to a command that does not read it
pub fn ignore_stdin_write_error(&mut self) -> &mut UCommand {
if self.bytes_into_stdin.is_none() {
panic!("{}", NO_STDIN_MEANINGLESS);
}
assert!(!self.bytes_into_stdin.is_none(), "{}", NO_STDIN_MEANINGLESS);
self.ignore_stdin_write_error = true;
self
}
@ -953,9 +965,7 @@ impl UCommand {
K: AsRef<OsStr>,
V: AsRef<OsStr>,
{
if self.has_run {
panic!("{}", ALREADY_RUN);
}
assert!(!self.has_run, "{}", ALREADY_RUN);
self.raw.env(key, val);
self
}
@ -974,9 +984,7 @@ impl UCommand {
/// Spawns the command, feeds the stdin if any, and returns the
/// child process immediately.
pub fn run_no_wait(&mut self) -> Child {
if self.has_run {
panic!("{}", ALREADY_RUN);
}
assert!(!self.has_run, "{}", ALREADY_RUN);
self.has_run = true;
log_info("run", &self.comm_string);
let mut child = self

View file

@ -1,3 +1,4 @@
#![allow(unused_imports)]
mod common;
use common::util::TestScenario;
@ -25,6 +26,7 @@ fn execution_phrase_double() {
#[test]
#[cfg(feature = "ls")]
#[cfg(any(unix, windows))]
fn execution_phrase_single() {
use std::process::Command;
@ -63,6 +65,7 @@ fn util_name_double() {
#[test]
#[cfg(feature = "sort")]
#[cfg(any(unix, windows))]
fn util_name_single() {
use std::{
io::Write,