1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 11:37:44 +00:00

Merge branch 'master' into chown_refactor_tests

This commit is contained in:
Jan Scheer 2021-04-17 11:48:43 +02:00
commit 9046e03a48
81 changed files with 711 additions and 668 deletions

2
Cargo.lock generated
View file

@ -1,7 +1,5 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "advapi32-sys"
version = "0.2.0"

View file

@ -111,6 +111,7 @@ fn basename(fullname: &str, suffix: &str) -> String {
}
}
#[allow(clippy::manual_strip)] // can be replaced with strip_suffix once the minimum rust version is 1.45
fn strip_suffix(name: &str, suffix: &str) -> String {
if name == suffix {
return name.to_owned();

View file

@ -286,7 +286,7 @@ impl Chgrper {
ret = match wrap_chgrp(path, &meta, self.dest_gid, follow, self.verbosity.clone()) {
Ok(n) => {
if n != "" {
if !n.is_empty() {
show_info!("{}", n);
}
0

View file

@ -171,13 +171,13 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
// of a prefix '-' if it's associated with MODE
// e.g. "chmod -v -xw -R FILE" -> "chmod -v xw -R FILE"
pub fn strip_minus_from_mode(args: &mut Vec<String>) -> bool {
for i in 0..args.len() {
if args[i].starts_with("-") {
if let Some(second) = args[i].chars().nth(1) {
for arg in args {
if arg.starts_with('-') {
if let Some(second) = arg.chars().nth(1) {
match second {
'r' | 'w' | 'x' | 'X' | 's' | 't' | 'u' | 'g' | 'o' | '0'..='7' => {
// TODO: use strip_prefix() once minimum rust version reaches 1.45.0
args[i] = args[i][1..args[i].len()].to_string();
*arg = arg[1..arg.len()].to_string();
return true;
}
_ => {}

View file

@ -391,7 +391,7 @@ impl Chowner {
self.verbosity.clone(),
) {
Ok(n) => {
if n != "" {
if !n.is_empty() {
show_info!("{}", n);
}
0
@ -446,7 +446,7 @@ impl Chowner {
self.verbosity.clone(),
) {
Ok(n) => {
if n != "" {
if !n.is_empty() {
show_info!("{}", n);
}
0

View file

@ -104,7 +104,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
_ => {
let mut vector: Vec<&str> = Vec::new();
for (&k, v) in matches.args.iter() {
vector.push(k.clone());
vector.push(k);
vector.push(&v.vals[0].to_str().unwrap());
}
vector
@ -133,7 +133,7 @@ fn set_context(root: &Path, options: &clap::ArgMatches) {
let userspec = match userspec_str {
Some(ref u) => {
let s: Vec<&str> = u.split(':').collect();
if s.len() != 2 || s.iter().any(|&spec| spec == "") {
if s.len() != 2 || s.iter().any(|&spec| spec.is_empty()) {
crash!(1, "invalid userspec: `{}`", u)
};
s
@ -142,16 +142,16 @@ fn set_context(root: &Path, options: &clap::ArgMatches) {
};
let (user, group) = if userspec.is_empty() {
(&user_str[..], &group_str[..])
(user_str, group_str)
} else {
(&userspec[0][..], &userspec[1][..])
(userspec[0], userspec[1])
};
enter_chroot(root);
set_groups_from_str(&groups_str[..]);
set_main_group(&group[..]);
set_user(&user[..]);
set_groups_from_str(groups_str);
set_main_group(group);
set_user(user);
}
fn enter_chroot(root: &Path) {

View file

@ -132,7 +132,9 @@ macro_rules! prompt_yes(
pub type CopyResult<T> = Result<T, Error>;
pub type Source = PathBuf;
pub type SourceSlice = Path;
pub type Target = PathBuf;
pub type TargetSlice = Path;
/// Specifies whether when overwrite files
#[derive(Clone, Eq, PartialEq)]
@ -547,14 +549,13 @@ impl FromStr for Attribute {
}
fn add_all_attributes() -> Vec<Attribute> {
let mut attr = Vec::new();
use Attribute::*;
let mut attr = vec![Ownership, Timestamps, Context, Xattr, Links];
#[cfg(unix)]
attr.push(Attribute::Mode);
attr.push(Attribute::Ownership);
attr.push(Attribute::Timestamps);
attr.push(Attribute::Context);
attr.push(Attribute::Xattr);
attr.push(Attribute::Links);
attr.insert(0, Mode);
attr
}
@ -665,7 +666,7 @@ impl TargetType {
///
/// Treat target as a dir if we have multiple sources or the target
/// exists and already is a directory
fn determine(sources: &[Source], target: &Target) -> TargetType {
fn determine(sources: &[Source], target: &TargetSlice) -> TargetType {
if sources.len() > 1 || target.is_dir() {
TargetType::Directory
} else {
@ -714,7 +715,7 @@ fn parse_path_args(path_args: &[String], options: &Options) -> CopyResult<(Vec<S
fn preserve_hardlinks(
hard_links: &mut Vec<(String, u64)>,
source: &std::path::PathBuf,
source: &std::path::Path,
dest: std::path::PathBuf,
found_hard_link: &mut bool,
) -> CopyResult<()> {
@ -788,7 +789,7 @@ fn preserve_hardlinks(
/// Behavior depends on `options`, see [`Options`] for details.
///
/// [`Options`]: ./struct.Options.html
fn copy(sources: &[Source], target: &Target, options: &Options) -> CopyResult<()> {
fn copy(sources: &[Source], target: &TargetSlice, options: &Options) -> CopyResult<()> {
let target_type = TargetType::determine(sources, target);
verify_target_type(target, &target_type)?;
@ -840,7 +841,7 @@ fn copy(sources: &[Source], target: &Target, options: &Options) -> CopyResult<()
fn construct_dest_path(
source_path: &Path,
target: &Target,
target: &TargetSlice,
target_type: &TargetType,
options: &Options,
) -> CopyResult<PathBuf> {
@ -870,8 +871,8 @@ fn construct_dest_path(
}
fn copy_source(
source: &Source,
target: &Target,
source: &SourceSlice,
target: &TargetSlice,
target_type: &TargetType,
options: &Options,
) -> CopyResult<()> {
@ -912,7 +913,7 @@ fn adjust_canonicalization(p: &Path) -> Cow<Path> {
///
/// Any errors encountered copying files in the tree will be logged but
/// will not cause a short-circuit.
fn copy_directory(root: &Path, target: &Target, options: &Options) -> CopyResult<()> {
fn copy_directory(root: &Path, target: &TargetSlice, options: &Options) -> CopyResult<()> {
if !options.recursive {
return Err(format!("omitting directory '{}'", root.display()).into());
}
@ -1068,6 +1069,7 @@ fn copy_attribute(source: &Path, dest: &Path, attribute: &Attribute) -> CopyResu
}
#[cfg(not(windows))]
#[allow(clippy::unnecessary_wraps)] // needed for windows version
fn symlink_file(source: &Path, dest: &Path, context: &str) -> CopyResult<()> {
match std::os::unix::fs::symlink(source, dest).context(context) {
Ok(_) => Ok(()),

View file

@ -406,7 +406,7 @@ fn cut_files(mut filenames: Vec<String>, mode: Mode) -> i32 {
continue;
}
if !path.metadata().is_ok() {
if path.metadata().is_err() {
show_error!("{}: No such file or directory", filename);
continue;
}
@ -487,7 +487,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
.help("filter field columns from the input source")
.takes_value(true)
.allow_hyphen_values(true)
.value_name("LIST")
.value_name("LIST")
.display_order(4),
)
.arg(
@ -535,40 +535,36 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
matches.value_of(options::CHARACTERS),
matches.value_of(options::FIELDS),
) {
(Some(byte_ranges), None, None) => {
list_to_ranges(&byte_ranges[..], complement).map(|ranges| {
Mode::Bytes(
ranges,
Options {
out_delim: Some(
matches
.value_of(options::OUTPUT_DELIMITER)
.unwrap_or_default()
.to_owned(),
),
zero_terminated: matches.is_present(options::ZERO_TERMINATED),
},
)
})
}
(None, Some(char_ranges), None) => {
list_to_ranges(&char_ranges[..], complement).map(|ranges| {
Mode::Characters(
ranges,
Options {
out_delim: Some(
matches
.value_of(options::OUTPUT_DELIMITER)
.unwrap_or_default()
.to_owned(),
),
zero_terminated: matches.is_present(options::ZERO_TERMINATED),
},
)
})
}
(Some(byte_ranges), None, None) => list_to_ranges(byte_ranges, complement).map(|ranges| {
Mode::Bytes(
ranges,
Options {
out_delim: Some(
matches
.value_of(options::OUTPUT_DELIMITER)
.unwrap_or_default()
.to_owned(),
),
zero_terminated: matches.is_present(options::ZERO_TERMINATED),
},
)
}),
(None, Some(char_ranges), None) => list_to_ranges(char_ranges, complement).map(|ranges| {
Mode::Characters(
ranges,
Options {
out_delim: Some(
matches
.value_of(options::OUTPUT_DELIMITER)
.unwrap_or_default()
.to_owned(),
),
zero_terminated: matches.is_present(options::ZERO_TERMINATED),
},
)
}),
(None, None, Some(field_ranges)) => {
list_to_ranges(&field_ranges[..], complement).and_then(|ranges| {
list_to_ranges(field_ranges, complement).and_then(|ranges| {
let out_delim = match matches.value_of(options::OUTPUT_DELIMITER) {
Some(s) => {
if s.is_empty() {

View file

@ -116,7 +116,6 @@ struct Options {
show_listed_fs: bool,
show_fs_type: bool,
show_inode_instead: bool,
print_grand_total: bool,
// block_size: usize,
human_readable_base: i64,
fs_selector: FsSelector,
@ -286,7 +285,6 @@ impl Options {
show_listed_fs: false,
show_fs_type: false,
show_inode_instead: false,
print_grand_total: false,
// block_size: match env::var("BLOCKSIZE") {
// Ok(size) => size.parse().unwrap(),
// Err(_) => 512,
@ -871,9 +869,6 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
if matches.is_present(OPT_ALL) {
opt.show_all_fs = true;
}
if matches.is_present(OPT_TOTAL) {
opt.print_grand_total = true;
}
if matches.is_present(OPT_INODES) {
opt.show_inode_instead = true;
}

View file

@ -15,7 +15,7 @@ use chrono::Local;
use std::collections::HashSet;
use std::env;
use std::fs;
use std::io::{stderr, Result, Write};
use std::io::{stderr, ErrorKind, Result, Write};
use std::iter;
#[cfg(not(windows))]
use std::os::unix::fs::MetadataExt;
@ -296,7 +296,21 @@ fn du(
}
}
}
Err(error) => show_error!("{}", error),
Err(error) => match error.kind() {
ErrorKind::PermissionDenied => {
let description = format!(
"cannot access '{}'",
entry
.path()
.as_os_str()
.to_str()
.unwrap_or("<Un-printable path>")
);
let error_message = "Permission denied";
show_error_custom_description!(description, "{}", error_message)
}
_ => show_error!("{}", error),
},
},
Err(error) => show_error!("{}", error),
}
@ -322,7 +336,7 @@ fn convert_size_human(size: u64, multiplier: u64, _block_size: u64) -> String {
}
}
if size == 0 {
return format!("0");
return "0".to_string();
}
format!("{}B", size)
}

View file

@ -51,7 +51,7 @@ fn print_expr_error(expr_error: &str) -> ! {
crash!(2, "{}", expr_error)
}
fn evaluate_ast(maybe_ast: Result<Box<syntax_tree::ASTNode>, String>) -> Result<String, String> {
fn evaluate_ast(maybe_ast: Result<Box<syntax_tree::AstNode>, String>) -> Result<String, String> {
if maybe_ast.is_err() {
Err(maybe_ast.err().unwrap())
} else {

View file

@ -17,10 +17,10 @@ use onig::{Regex, RegexOptions, Syntax};
use crate::tokens::Token;
type TokenStack = Vec<(usize, Token)>;
pub type OperandsList = Vec<Box<ASTNode>>;
pub type OperandsList = Vec<Box<AstNode>>;
#[derive(Debug)]
pub enum ASTNode {
pub enum AstNode {
Leaf {
token_idx: usize,
value: String,
@ -31,7 +31,7 @@ pub enum ASTNode {
operands: OperandsList,
},
}
impl ASTNode {
impl AstNode {
fn debug_dump(&self) {
self.debug_dump_impl(1);
}
@ -40,7 +40,7 @@ impl ASTNode {
print!("\t",);
}
match *self {
ASTNode::Leaf {
AstNode::Leaf {
ref token_idx,
ref value,
} => println!(
@ -49,7 +49,7 @@ impl ASTNode {
token_idx,
self.evaluate()
),
ASTNode::Node {
AstNode::Node {
ref token_idx,
ref op_type,
ref operands,
@ -67,23 +67,23 @@ impl ASTNode {
}
}
fn new_node(token_idx: usize, op_type: &str, operands: OperandsList) -> Box<ASTNode> {
Box::new(ASTNode::Node {
fn new_node(token_idx: usize, op_type: &str, operands: OperandsList) -> Box<AstNode> {
Box::new(AstNode::Node {
token_idx,
op_type: op_type.into(),
operands,
})
}
fn new_leaf(token_idx: usize, value: &str) -> Box<ASTNode> {
Box::new(ASTNode::Leaf {
fn new_leaf(token_idx: usize, value: &str) -> Box<AstNode> {
Box::new(AstNode::Leaf {
token_idx,
value: value.into(),
})
}
pub fn evaluate(&self) -> Result<String, String> {
match *self {
ASTNode::Leaf { ref value, .. } => Ok(value.clone()),
ASTNode::Node { ref op_type, .. } => match self.operand_values() {
AstNode::Leaf { ref value, .. } => Ok(value.clone()),
AstNode::Node { ref op_type, .. } => match self.operand_values() {
Err(reason) => Err(reason),
Ok(operand_values) => match op_type.as_ref() {
"+" => infix_operator_two_ints(
@ -161,7 +161,7 @@ impl ASTNode {
}
}
pub fn operand_values(&self) -> Result<Vec<String>, String> {
if let ASTNode::Node { ref operands, .. } = *self {
if let AstNode::Node { ref operands, .. } = *self {
let mut out = Vec::with_capacity(operands.len());
for operand in operands {
match operand.evaluate() {
@ -178,7 +178,7 @@ impl ASTNode {
pub fn tokens_to_ast(
maybe_tokens: Result<Vec<(usize, Token)>, String>,
) -> Result<Box<ASTNode>, String> {
) -> Result<Box<AstNode>, String> {
if maybe_tokens.is_err() {
Err(maybe_tokens.err().unwrap())
} else {
@ -212,7 +212,7 @@ pub fn tokens_to_ast(
}
}
fn maybe_dump_ast(result: &Result<Box<ASTNode>, String>) {
fn maybe_dump_ast(result: &Result<Box<AstNode>, String>) {
use std::env;
if let Ok(debug_var) = env::var("EXPR_DEBUG_AST") {
if debug_var == "1" {
@ -238,11 +238,11 @@ fn maybe_dump_rpn(rpn: &TokenStack) {
}
}
fn ast_from_rpn(rpn: &mut TokenStack) -> Result<Box<ASTNode>, String> {
fn ast_from_rpn(rpn: &mut TokenStack) -> Result<Box<AstNode>, String> {
match rpn.pop() {
None => Err("syntax error (premature end of expression)".to_owned()),
Some((token_idx, Token::Value { value })) => Ok(ASTNode::new_leaf(token_idx, &value)),
Some((token_idx, Token::Value { value })) => Ok(AstNode::new_leaf(token_idx, &value)),
Some((token_idx, Token::InfixOp { value, .. })) => {
maybe_ast_node(token_idx, &value, 2, rpn)
@ -262,7 +262,7 @@ fn maybe_ast_node(
op_type: &str,
arity: usize,
rpn: &mut TokenStack,
) -> Result<Box<ASTNode>, String> {
) -> Result<Box<AstNode>, String> {
let mut operands = Vec::with_capacity(arity);
for _ in 0..arity {
match ast_from_rpn(rpn) {
@ -271,7 +271,7 @@ fn maybe_ast_node(
}
}
operands.reverse();
Ok(ASTNode::new_node(token_idx, op_type, operands))
Ok(AstNode::new_node(token_idx, op_type, operands))
}
fn move_rest_of_ops_to_out(

View file

@ -267,7 +267,7 @@ impl<'a> ParagraphStream<'a> {
#[allow(clippy::match_like_matches_macro)]
// `matches!(...)` macro not stabilized until rust v1.42
l_slice[..colon_posn].chars().all(|x| match x as usize {
y if y < 33 || y > 126 => false,
y if !(33..=126).contains(&y) => false,
_ => true,
})
}

View file

@ -66,7 +66,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
.takes_value(true),
)
.arg(Arg::with_name(options::FILE).hidden(true).multiple(true))
.get_matches_from(args.clone());
.get_matches_from(args);
let bytes = matches.is_present(options::BYTES);
let spaces = matches.is_present(options::SPACES);

View file

@ -78,7 +78,7 @@ fn detect_algo<'a>(
"sha512sum" => ("SHA512", Box::new(Sha512::new()) as Box<dyn Digest>, 512),
"b2sum" => ("BLAKE2", Box::new(Blake2b::new(64)) as Box<dyn Digest>, 512),
"sha3sum" => match matches.value_of("bits") {
Some(bits_str) => match usize::from_str_radix(&bits_str, 10) {
Some(bits_str) => match (&bits_str).parse::<usize>() {
Ok(224) => (
"SHA3-224",
Box::new(Sha3_224::new()) as Box<dyn Digest>,
@ -128,7 +128,7 @@ fn detect_algo<'a>(
512,
),
"shake128sum" => match matches.value_of("bits") {
Some(bits_str) => match usize::from_str_radix(&bits_str, 10) {
Some(bits_str) => match (&bits_str).parse::<usize>() {
Ok(bits) => (
"SHAKE128",
Box::new(Shake128::new()) as Box<dyn Digest>,
@ -139,7 +139,7 @@ fn detect_algo<'a>(
None => crash!(1, "--bits required for SHAKE-128"),
},
"shake256sum" => match matches.value_of("bits") {
Some(bits_str) => match usize::from_str_radix(&bits_str, 10) {
Some(bits_str) => match (&bits_str).parse::<usize>() {
Ok(bits) => (
"SHAKE256",
Box::new(Shake256::new()) as Box<dyn Digest>,
@ -182,7 +182,7 @@ fn detect_algo<'a>(
}
if matches.is_present("sha3") {
match matches.value_of("bits") {
Some(bits_str) => match usize::from_str_radix(&bits_str, 10) {
Some(bits_str) => match (&bits_str).parse::<usize>() {
Ok(224) => set_or_crash(
"SHA3-224",
Box::new(Sha3_224::new()) as Box<dyn Digest>,
@ -226,7 +226,7 @@ fn detect_algo<'a>(
}
if matches.is_present("shake128") {
match matches.value_of("bits") {
Some(bits_str) => match usize::from_str_radix(&bits_str, 10) {
Some(bits_str) => match (&bits_str).parse::<usize>() {
Ok(bits) => set_or_crash("SHAKE128", Box::new(Shake128::new()), bits),
Err(err) => crash!(1, "{}", err),
},
@ -235,7 +235,7 @@ fn detect_algo<'a>(
}
if matches.is_present("shake256") {
match matches.value_of("bits") {
Some(bits_str) => match usize::from_str_radix(&bits_str, 10) {
Some(bits_str) => match (&bits_str).parse::<usize>() {
Ok(bits) => set_or_crash("SHAKE256", Box::new(Shake256::new()), bits),
Err(err) => crash!(1, "{}", err),
},
@ -253,7 +253,7 @@ fn detect_algo<'a>(
// TODO: return custom error type
fn parse_bit_num(arg: &str) -> Result<usize, ParseIntError> {
usize::from_str_radix(arg, 10)
arg.parse()
}
fn is_valid_bit_num(arg: String) -> Result<(), String> {

View file

@ -625,7 +625,7 @@ mod tests {
assert_eq!(arg_outputs("head"), Ok("head".to_owned()));
}
#[test]
#[cfg(linux)]
#[cfg(target_os = "linux")]
fn test_arg_iterate_bad_encoding() {
let invalid = unsafe { std::str::from_utf8_unchecked(b"\x80\x81") };
// this arises from a conversion from OsString to &str

View file

@ -302,7 +302,7 @@ fn behavior(matches: &ArgMatches) -> Result<Behavior, i32> {
let specified_mode: Option<u32> = if matches.is_present(OPT_MODE) {
match matches.value_of(OPT_MODE) {
Some(x) => match mode::parse(&x[..], considering_dir) {
Some(x) => match mode::parse(x, considering_dir) {
Ok(y) => Some(y),
Err(err) => {
show_error!("Invalid mode string: {}", err);
@ -429,7 +429,7 @@ fn standard(paths: Vec<String>, b: Behavior) -> i32 {
/// _files_ must all exist as non-directories.
/// _target_dir_ must be a directory.
///
fn copy_files_into_dir(files: &[PathBuf], target_dir: &PathBuf, b: &Behavior) -> i32 {
fn copy_files_into_dir(files: &[PathBuf], target_dir: &Path, b: &Behavior) -> i32 {
if !target_dir.is_dir() {
show_error!("target '{}' is not a directory", target_dir.display());
return 1;
@ -453,7 +453,7 @@ fn copy_files_into_dir(files: &[PathBuf], target_dir: &PathBuf, b: &Behavior) ->
continue;
}
let mut targetpath = target_dir.clone().to_path_buf();
let mut targetpath = target_dir.to_path_buf();
let filename = sourcepath.components().last().unwrap();
targetpath.push(filename);
@ -478,7 +478,7 @@ fn copy_files_into_dir(files: &[PathBuf], target_dir: &PathBuf, b: &Behavior) ->
/// _file_ must exist as a non-directory.
/// _target_ must be a non-directory
///
fn copy_file_to_file(file: &PathBuf, target: &PathBuf, b: &Behavior) -> i32 {
fn copy_file_to_file(file: &Path, target: &Path, b: &Behavior) -> i32 {
if copy(file, &target, b).is_err() {
1
} else {
@ -497,7 +497,7 @@ fn copy_file_to_file(file: &PathBuf, target: &PathBuf, b: &Behavior) -> i32 {
///
/// If the copy system call fails, we print a verbose error and return an empty error value.
///
fn copy(from: &PathBuf, to: &PathBuf, b: &Behavior) -> Result<(), ()> {
fn copy(from: &Path, to: &Path, b: &Behavior) -> Result<(), ()> {
if b.compare && !need_copy(from, to, b) {
return Ok(());
}
@ -556,7 +556,7 @@ fn copy(from: &PathBuf, to: &PathBuf, b: &Behavior) -> Result<(), ()> {
};
let gid = meta.gid();
match wrap_chown(
to.as_path(),
to,
&meta,
Some(owner_id),
Some(gid),
@ -582,7 +582,7 @@ fn copy(from: &PathBuf, to: &PathBuf, b: &Behavior) -> Result<(), ()> {
Ok(g) => g,
_ => crash!(1, "no such group: {}", b.group),
};
match wrap_chgrp(to.as_path(), &meta, group_id, false, Verbosity::Normal) {
match wrap_chgrp(to, &meta, group_id, false, Verbosity::Normal) {
Ok(n) => {
if !n.is_empty() {
show_info!("{}", n);
@ -601,7 +601,7 @@ fn copy(from: &PathBuf, to: &PathBuf, b: &Behavior) -> Result<(), ()> {
let modified_time = FileTime::from_last_modification_time(&meta);
let accessed_time = FileTime::from_last_access_time(&meta);
match set_file_times(to.as_path(), accessed_time, modified_time) {
match set_file_times(to, accessed_time, modified_time) {
Ok(_) => {}
Err(e) => show_info!("{}", e),
}
@ -630,7 +630,7 @@ fn copy(from: &PathBuf, to: &PathBuf, b: &Behavior) -> Result<(), ()> {
///
/// Crashes the program if a nonexistent owner or group is specified in _b_.
///
fn need_copy(from: &PathBuf, to: &PathBuf, b: &Behavior) -> bool {
fn need_copy(from: &Path, to: &Path, b: &Behavior) -> bool {
let from_meta = match fs::metadata(from) {
Ok(meta) => meta,
Err(_) => return true,

View file

@ -303,7 +303,7 @@ fn exec(files: &[PathBuf], settings: &Settings) -> i32 {
}
}
fn link_files_in_dir(files: &[PathBuf], target_dir: &PathBuf, settings: &Settings) -> i32 {
fn link_files_in_dir(files: &[PathBuf], target_dir: &Path, settings: &Settings) -> i32 {
if !target_dir.is_dir() {
show_error!("target '{}' is not a directory", target_dir.display());
return 1;
@ -329,7 +329,7 @@ fn link_files_in_dir(files: &[PathBuf], target_dir: &PathBuf, settings: &Setting
};
}
}
target_dir.clone()
target_dir.to_path_buf()
} else {
match srcpath.as_os_str().to_str() {
Some(name) => {
@ -370,7 +370,7 @@ fn link_files_in_dir(files: &[PathBuf], target_dir: &PathBuf, settings: &Setting
}
}
fn relative_path<'a>(src: &PathBuf, dst: &PathBuf) -> Result<Cow<'a, Path>> {
fn relative_path<'a>(src: &Path, dst: &Path) -> Result<Cow<'a, Path>> {
let abssrc = canonicalize(src, CanonicalizeMode::Normal)?;
let absdst = canonicalize(dst, CanonicalizeMode::Normal)?;
let suffix_pos = abssrc
@ -390,7 +390,7 @@ fn relative_path<'a>(src: &PathBuf, dst: &PathBuf) -> Result<Cow<'a, Path>> {
Ok(result.into())
}
fn link(src: &PathBuf, dst: &PathBuf, settings: &Settings) -> Result<()> {
fn link(src: &Path, dst: &Path, settings: &Settings) -> Result<()> {
let mut backup_path = None;
let source: Cow<'_, Path> = if settings.relative {
relative_path(&src, dst)?
@ -453,13 +453,13 @@ fn read_yes() -> bool {
}
}
fn simple_backup_path(path: &PathBuf, suffix: &str) -> PathBuf {
fn simple_backup_path(path: &Path, suffix: &str) -> PathBuf {
let mut p = path.as_os_str().to_str().unwrap().to_owned();
p.push_str(suffix);
PathBuf::from(p)
}
fn numbered_backup_path(path: &PathBuf) -> PathBuf {
fn numbered_backup_path(path: &Path) -> PathBuf {
let mut i: u64 = 1;
loop {
let new_path = simple_backup_path(path, &format!(".~{}~", i));
@ -470,7 +470,7 @@ fn numbered_backup_path(path: &PathBuf) -> PathBuf {
}
}
fn existing_backup_path(path: &PathBuf, suffix: &str) -> PathBuf {
fn existing_backup_path(path: &Path, suffix: &str) -> PathBuf {
let test_path = simple_backup_path(path, &".~1~".to_owned());
if test_path.exists() {
return numbered_backup_path(path);

View file

@ -370,6 +370,7 @@ impl Config {
})
.or_else(|| termsize::get().map(|s| s.cols));
#[allow(clippy::needless_bool)]
let show_control = if options.is_present(options::HIDE_CONTROL_CHARS) {
false
} else if options.is_present(options::SHOW_CONTROL_CHARS) {
@ -1042,7 +1043,7 @@ fn sort_entries(entries: &mut Vec<PathBuf>, config: &Config) {
.sort_by_key(|k| Reverse(get_metadata(k, config).map(|md| md.len()).unwrap_or(0))),
// The default sort in GNU ls is case insensitive
Sort::Name => entries.sort_by_key(|k| k.to_string_lossy().to_lowercase()),
Sort::Version => entries.sort_by(version_cmp::version_cmp),
Sort::Version => entries.sort_by(|a, b| version_cmp::version_cmp(a, b)),
Sort::None => {}
}
@ -1076,7 +1077,7 @@ fn should_display(entry: &DirEntry, config: &Config) -> bool {
true
}
fn enter_directory(dir: &PathBuf, config: &Config) {
fn enter_directory(dir: &Path, config: &Config) {
let mut entries: Vec<_> = safe_unwrap!(fs::read_dir(dir).and_then(Iterator::collect));
entries.retain(|e| should_display(e, config));
@ -1101,7 +1102,7 @@ fn enter_directory(dir: &PathBuf, config: &Config) {
}
}
fn get_metadata(entry: &PathBuf, config: &Config) -> std::io::Result<Metadata> {
fn get_metadata(entry: &Path, config: &Config) -> std::io::Result<Metadata> {
if config.dereference {
entry.metadata().or_else(|_| entry.symlink_metadata())
} else {
@ -1109,7 +1110,7 @@ fn get_metadata(entry: &PathBuf, config: &Config) -> std::io::Result<Metadata> {
}
}
fn display_dir_entry_size(entry: &PathBuf, config: &Config) -> (usize, usize) {
fn display_dir_entry_size(entry: &Path, config: &Config) -> (usize, usize) {
if let Ok(md) = get_metadata(entry, config) {
(
display_symlink_count(&md).len(),
@ -1204,7 +1205,7 @@ fn display_grid(names: impl Iterator<Item = Cell>, width: u16, direction: Direct
use uucore::fs::display_permissions;
fn display_item_long(
item: &PathBuf,
item: &Path,
strip: Option<&Path>,
max_links: usize,
max_size: usize,

View file

@ -1,8 +1,9 @@
use std::{cmp::Ordering, path::PathBuf};
use std::cmp::Ordering;
use std::path::Path;
/// Compare pathbufs in a way that matches the GNU version sort, meaning that
/// Compare paths in a way that matches the GNU version sort, meaning that
/// numbers get sorted in a natural way.
pub(crate) fn version_cmp(a: &PathBuf, b: &PathBuf) -> Ordering {
pub(crate) fn version_cmp(a: &Path, b: &Path) -> Ordering {
let a_string = a.to_string_lossy();
let b_string = b.to_string_lossy();
let mut a = a_string.chars().peekable();

View file

@ -335,7 +335,7 @@ fn exec(files: &[PathBuf], b: Behavior) -> i32 {
0
}
fn move_files_into_dir(files: &[PathBuf], target_dir: &PathBuf, b: &Behavior) -> i32 {
fn move_files_into_dir(files: &[PathBuf], target_dir: &Path, b: &Behavior) -> i32 {
if !target_dir.is_dir() {
show_error!("target {} is not a directory", target_dir.display());
return 1;
@ -373,7 +373,7 @@ fn move_files_into_dir(files: &[PathBuf], target_dir: &PathBuf, b: &Behavior) ->
}
}
fn rename(from: &PathBuf, to: &PathBuf, b: &Behavior) -> io::Result<()> {
fn rename(from: &Path, to: &Path, b: &Behavior) -> io::Result<()> {
let mut backup_path = None;
if to.exists() {
@ -429,7 +429,7 @@ fn rename(from: &PathBuf, to: &PathBuf, b: &Behavior) -> io::Result<()> {
/// A wrapper around `fs::rename`, so that if it fails, we try falling back on
/// copying and removing.
fn rename_with_fallback(from: &PathBuf, to: &PathBuf) -> io::Result<()> {
fn rename_with_fallback(from: &Path, to: &Path) -> io::Result<()> {
if fs::rename(from, to).is_err() {
// Get metadata without following symlinks
let metadata = from.symlink_metadata()?;
@ -464,7 +464,7 @@ fn rename_with_fallback(from: &PathBuf, to: &PathBuf) -> io::Result<()> {
/// Move the given symlink to the given destination. On Windows, dangling
/// symlinks return an error.
#[inline]
fn rename_symlink_fallback(from: &PathBuf, to: &PathBuf) -> io::Result<()> {
fn rename_symlink_fallback(from: &Path, to: &Path) -> io::Result<()> {
let path_symlink_points_to = fs::read_link(from)?;
#[cfg(unix)]
{
@ -507,20 +507,20 @@ fn read_yes() -> bool {
}
}
fn simple_backup_path(path: &PathBuf, suffix: &str) -> PathBuf {
fn simple_backup_path(path: &Path, suffix: &str) -> PathBuf {
let mut p = path.to_string_lossy().into_owned();
p.push_str(suffix);
PathBuf::from(p)
}
fn numbered_backup_path(path: &PathBuf) -> PathBuf {
fn numbered_backup_path(path: &Path) -> PathBuf {
(1_u64..)
.map(|i| path.with_extension(format!("~{}~", i)))
.find(|p| !p.exists())
.expect("cannot create backup")
}
fn existing_backup_path(path: &PathBuf, suffix: &str) -> PathBuf {
fn existing_backup_path(path: &Path, suffix: &str) -> PathBuf {
let test_path = path.with_extension("~1~");
if test_path.exists() {
numbered_backup_path(path)
@ -529,7 +529,7 @@ fn existing_backup_path(path: &PathBuf, suffix: &str) -> PathBuf {
}
}
fn is_empty_dir(path: &PathBuf) -> bool {
fn is_empty_dir(path: &Path) -> bool {
match fs::read_dir(path) {
Ok(contents) => contents.peekable().peek().is_none(),
Err(_e) => false,

View file

@ -118,7 +118,7 @@ struct OdOptions {
}
impl OdOptions {
fn new<'a>(matches: ArgMatches<'a>, args: Vec<String>) -> Result<OdOptions, String> {
fn new(matches: ArgMatches, args: Vec<String>) -> Result<OdOptions, String> {
let byte_order = match matches.value_of(options::ENDIAN) {
None => ByteOrder::Native,
Some("little") => ByteOrder::Little,

View file

@ -63,7 +63,7 @@ pub fn parse_inputs(matches: &dyn CommandLineOpts) -> Result<CommandLineInputs,
}
if input_strings.len() == 2 {
return Ok(CommandLineInputs::FileAndOffset((
input_strings[0].clone().to_owned(),
input_strings[0].to_string(),
n,
None,
)));
@ -106,7 +106,7 @@ pub fn parse_inputs_traditional(input_strings: Vec<&str>) -> Result<CommandLineI
Some(m),
))),
(_, Ok(m)) => Ok(CommandLineInputs::FileAndOffset((
input_strings[0].clone().to_owned(),
input_strings[0].to_string(),
m,
None,
))),
@ -118,7 +118,7 @@ pub fn parse_inputs_traditional(input_strings: Vec<&str>) -> Result<CommandLineI
let label = parse_offset_operand(&input_strings[2]);
match (offset, label) {
(Ok(n), Ok(m)) => Ok(CommandLineInputs::FileAndOffset((
input_strings[0].clone().to_owned(),
input_strings[0].to_string(),
n,
Some(m),
))),

View file

@ -15,7 +15,6 @@ use uucore::utmpx::{self, time, Utmpx};
use std::io::prelude::*;
use std::io::BufReader;
use std::io::Result as IOResult;
use std::fs::File;
use std::os::unix::fs::MetadataExt;
@ -136,12 +135,8 @@ The utmp file will be {}",
};
if do_short_format {
if let Err(e) = pk.short_pinky() {
show_usage_error!("{}", e);
1
} else {
0
}
pk.short_pinky();
0
} else {
pk.long_pinky()
}
@ -282,7 +277,7 @@ impl Pinky {
println!();
}
fn short_pinky(&self) -> IOResult<()> {
fn short_pinky(&self) {
if self.include_heading {
self.print_heading();
}
@ -295,7 +290,6 @@ impl Pinky {
}
}
}
Ok(())
}
fn long_pinky(&self) -> i32 {

View file

@ -199,8 +199,7 @@ pub fn arrnum_int_add(arrnum: &[u8], basenum: u8, base_ten_int_term: u8) -> Vec<
}
pub fn base_conv_vec(src: &[u8], radix_src: u8, radix_dest: u8) -> Vec<u8> {
let mut result: Vec<u8> = Vec::new();
result.push(0);
let mut result = vec![0];
for i in src {
result = arrnum_int_mult(&result, radix_dest, radix_src);
result = arrnum_int_add(&result, radix_dest, *i);
@ -226,8 +225,7 @@ pub fn base_conv_float(src: &[u8], radix_src: u8, radix_dest: u8) -> f64 {
// to implement this for arbitrary string input.
// until then, the below operates as an outline
// of how it would work.
let mut result: Vec<u8> = Vec::new();
result.push(0);
let result: Vec<u8> = vec![0];
let mut factor: f64 = 1_f64;
let radix_src_float: f64 = f64::from(radix_src);
let mut r: f64 = 0_f64;

View file

@ -263,9 +263,5 @@ pub fn num_format(field: &FormatField, in_str_opt: Option<&String>) -> Option<St
};
// if we have a formatPrimitive, print its results
// according to the field-char appropriate Formatter
if let Some(prim) = prim_opt {
Some(fmtr.primitive_to_str(&prim, field.clone()))
} else {
None
}
prim_opt.map(|prim| fmtr.primitive_to_str(&prim, field.clone()))
}

View file

@ -177,14 +177,14 @@ fn get_config(matches: &clap::ArgMatches) -> Config {
}
if matches.is_present(options::WIDTH) {
let width_str = matches.value_of(options::WIDTH).expect(err_msg).to_string();
config.line_width = crash_if_err!(1, usize::from_str_radix(&width_str, 10));
config.line_width = crash_if_err!(1, (&width_str).parse::<usize>());
}
if matches.is_present(options::GAP_SIZE) {
let gap_str = matches
.value_of(options::GAP_SIZE)
.expect(err_msg)
.to_string();
config.gap_size = crash_if_err!(1, usize::from_str_radix(&gap_str, 10));
config.gap_size = crash_if_err!(1, (&gap_str).parse::<usize>());
}
if matches.is_present(options::FORMAT_ROFF) {
config.format = OutFormat::Roff;

View file

@ -13,7 +13,7 @@ extern crate uucore;
use clap::{App, Arg};
use std::fs;
use std::io::{stdout, Write};
use std::path::PathBuf;
use std::path::{Path, PathBuf};
use uucore::fs::{canonicalize, CanonicalizeMode};
const NAME: &str = "readlink";
@ -160,8 +160,8 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
0
}
fn show(path: &PathBuf, no_newline: bool, use_zero: bool) {
let path = path.as_path().to_str().unwrap();
fn show(path: &Path, no_newline: bool, use_zero: bool) {
let path = path.to_str().unwrap();
if use_zero {
print!("{}\0", path);
} else if no_newline {

View file

@ -12,7 +12,7 @@ extern crate uucore;
use clap::{App, Arg};
use std::fs;
use std::path::PathBuf;
use std::path::{Path, PathBuf};
use uucore::fs::{canonicalize, CanonicalizeMode};
static ABOUT: &str = "print the resolved path";
@ -82,7 +82,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
retcode
}
fn resolve_path(p: &PathBuf, strip: bool, zero: bool, quiet: bool) -> bool {
fn resolve_path(p: &Path, strip: bool, zero: bool, quiet: bool) -> bool {
let abs = canonicalize(p, CanonicalizeMode::Normal).unwrap();
if strip {

View file

@ -176,7 +176,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
} else if matches.is_present(OPT_PROMPT_MORE) {
InteractiveMode::Once
} else if matches.is_present(OPT_INTERACTIVE) {
match &matches.value_of(OPT_INTERACTIVE).unwrap()[..] {
match matches.value_of(OPT_INTERACTIVE).unwrap() {
"none" => InteractiveMode::None,
"once" => InteractiveMode::Once,
"always" => InteractiveMode::Always,

View file

@ -102,7 +102,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
let mut largest_dec = 0;
let mut padding = 0;
let first = if numbers.len() > 1 {
let slice = &numbers[0][..];
let slice = numbers[0];
let len = slice.len();
let dec = slice.find('.').unwrap_or(len);
largest_dec = len - dec;
@ -118,7 +118,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
1.0
};
let increment = if numbers.len() > 2 {
let slice = &numbers[1][..];
let slice = numbers[1];
let len = slice.len();
let dec = slice.find('.').unwrap_or(len);
largest_dec = cmp::max(largest_dec, len - dec);
@ -134,11 +134,11 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
1.0
};
if increment == 0.0 {
show_error!("increment value: '{}'", &numbers[1][..]);
show_error!("increment value: '{}'", numbers[1]);
return 1;
}
let last = {
let slice = &numbers[numbers.len() - 1][..];
let slice = numbers[numbers.len() - 1];
padding = cmp::max(padding, slice.find('.').unwrap_or_else(|| slice.len()));
match parse_float(slice) {
Ok(n) => n,

View file

@ -363,10 +363,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
let force = matches.is_present(options::FORCE);
let remove = matches.is_present(options::REMOVE);
let size_arg = match matches.value_of(options::SIZE) {
Some(s) => Some(s.to_string()),
None => None,
};
let size_arg = matches.value_of(options::SIZE).map(|s| s.to_string());
let size = get_size(size_arg);
let exact = matches.is_present(options::EXACT) && size.is_none(); // if -s is given, ignore -x
let zero = matches.is_present(options::ZERO);
@ -439,6 +436,7 @@ fn pass_name(pass_type: PassType) -> String {
}
}
#[allow(clippy::too_many_arguments)]
fn wipe_file(
path_str: &str,
n_passes: usize,
@ -472,12 +470,9 @@ fn wipe_file(
let mut perms = metadata.permissions();
perms.set_readonly(false);
match fs::set_permissions(path, perms) {
Err(e) => {
show_error!("{}", e);
return;
}
_ => {}
if let Err(e) = fs::set_permissions(path, perms) {
show_error!("{}", e);
return;
}
}

View file

@ -677,7 +677,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
.arg(
Arg::with_name(OPT_PARALLEL)
.long(OPT_PARALLEL)
.help("change the number of threads running concurrently to N")
.help("change the number of threads running concurrently to NUM_THREADS")
.takes_value(true)
.value_name("NUM_THREADS"),
)
@ -1226,7 +1226,7 @@ fn month_parse(line: &str) -> Month {
// GNU splits at any 3 letter match "JUNNNN" is JUN
let pattern = if line.trim().len().ge(&3) {
// Split a 3 and get first element of tuple ".0"
line.split_at(3).0
line.trim().split_at(3).0
} else {
""
};
@ -1262,10 +1262,21 @@ fn month_compare(a: &str, b: &str) -> Ordering {
}
}
fn version_parse(a: &str) -> Version {
let result = Version::parse(a);
match result {
Ok(vers_a) => vers_a,
// Non-version lines parse to 0.0.0
Err(_e) => Version::parse("0.0.0").unwrap(),
}
}
fn version_compare(a: &str, b: &str) -> Ordering {
#![allow(clippy::comparison_chain)]
let ver_a = Version::parse(a);
let ver_b = Version::parse(b);
let ver_a = version_parse(a);
let ver_b = version_parse(b);
// Version::cmp is not implemented; implement comparison directly
if ver_a > ver_b {
Ordering::Greater

View file

@ -35,8 +35,8 @@ extern "C" {
fn set_buffer(stream: *mut FILE, value: &str) {
let (mode, size): (c_int, size_t) = match value {
"0" => (_IONBF, 0 as size_t),
"L" => (_IOLBF, 0 as size_t),
"0" => (_IONBF, 0_usize),
"L" => (_IOLBF, 0_usize),
input => {
let buff_size: usize = match input.parse() {
Ok(num) => num,

View file

@ -141,12 +141,10 @@ fn parse_size(size: &str) -> Option<u64> {
fn check_option(matches: &ArgMatches, name: &str) -> Result<BufferType, ProgramOptionsError> {
match matches.value_of(name) {
Some(value) => match &value[..] {
Some(value) => match value {
"L" => {
if name == options::INPUT {
Err(ProgramOptionsError(format!(
"line buffering stdin is meaningless"
)))
Err(ProgramOptionsError("line buffering stdin is meaningless".to_string()))
} else {
Ok(BufferType::Line)
}

View file

@ -75,7 +75,7 @@ fn open(name: &str) -> Result<Box<dyn Read>> {
"Is a directory",
));
};
if !path.metadata().is_ok() {
if path.metadata().is_err() {
return Err(std::io::Error::new(
std::io::ErrorKind::NotFound,
"No such file or directory",

View file

@ -90,7 +90,7 @@ fn tac(filenames: Vec<String>, before: bool, _: bool, separator: &str) -> i32 {
Box::new(stdin()) as Box<dyn Read>
} else {
let path = Path::new(filename);
if path.is_dir() || !path.metadata().is_ok() {
if path.is_dir() || path.metadata().is_err() {
show_error!(
"failed to open '{}' for reading: No such file or directory",
filename

View file

@ -55,16 +55,16 @@ fn two(args: &[&[u8]], error: &mut bool) -> bool {
b"-d" => path(args[1], PathCondition::Directory),
b"-e" => path(args[1], PathCondition::Exists),
b"-f" => path(args[1], PathCondition::Regular),
b"-g" => path(args[1], PathCondition::GroupIDFlag),
b"-g" => path(args[1], PathCondition::GroupIdFlag),
b"-h" => path(args[1], PathCondition::SymLink),
b"-L" => path(args[1], PathCondition::SymLink),
b"-n" => one(&args[1..]),
b"-p" => path(args[1], PathCondition::FIFO),
b"-p" => path(args[1], PathCondition::Fifo),
b"-r" => path(args[1], PathCondition::Readable),
b"-S" => path(args[1], PathCondition::Socket),
b"-s" => path(args[1], PathCondition::NonEmpty),
b"-t" => isatty(args[1]),
b"-u" => path(args[1], PathCondition::UserIDFlag),
b"-u" => path(args[1], PathCondition::UserIdFlag),
b"-w" => path(args[1], PathCondition::Writable),
b"-x" => path(args[1], PathCondition::Executable),
b"-z" => !one(&args[1..]),
@ -322,13 +322,13 @@ enum PathCondition {
Directory,
Exists,
Regular,
GroupIDFlag,
GroupIdFlag,
SymLink,
FIFO,
Fifo,
Readable,
Socket,
NonEmpty,
UserIDFlag,
UserIdFlag,
Writable,
Executable,
}
@ -390,13 +390,13 @@ fn path(path: &[u8], cond: PathCondition) -> bool {
PathCondition::Directory => file_type.is_dir(),
PathCondition::Exists => true,
PathCondition::Regular => file_type.is_file(),
PathCondition::GroupIDFlag => metadata.mode() & S_ISGID != 0,
PathCondition::GroupIdFlag => metadata.mode() & S_ISGID != 0,
PathCondition::SymLink => metadata.file_type().is_symlink(),
PathCondition::FIFO => file_type.is_fifo(),
PathCondition::Fifo => file_type.is_fifo(),
PathCondition::Readable => perm(metadata, Permission::Read),
PathCondition::Socket => file_type.is_socket(),
PathCondition::NonEmpty => metadata.size() > 0,
PathCondition::UserIDFlag => metadata.mode() & S_ISUID != 0,
PathCondition::UserIdFlag => metadata.mode() & S_ISUID != 0,
PathCondition::Writable => perm(metadata, Permission::Write),
PathCondition::Executable => perm(metadata, Permission::Execute),
}
@ -416,13 +416,13 @@ fn path(path: &[u8], cond: PathCondition) -> bool {
PathCondition::Directory => stat.is_dir(),
PathCondition::Exists => true,
PathCondition::Regular => stat.is_file(),
PathCondition::GroupIDFlag => false,
PathCondition::GroupIdFlag => false,
PathCondition::SymLink => false,
PathCondition::FIFO => false,
PathCondition::Fifo => false,
PathCondition::Readable => false, // TODO
PathCondition::Socket => false,
PathCondition::NonEmpty => stat.len() > 0,
PathCondition::UserIDFlag => false,
PathCondition::UserIdFlag => false,
PathCondition::Writable => false, // TODO
PathCondition::Executable => false, // TODO
}

View file

@ -18,6 +18,7 @@ use filetime::*;
use std::fs::{self, File};
use std::io::Error;
use std::path::Path;
use std::process;
static VERSION: &str = env!("CARGO_PKG_VERSION");
static ABOUT: &str = "Update the access and modification times of each FILE to the current time.";
@ -137,7 +138,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
let (mut atime, mut mtime) = if matches.is_present(options::sources::REFERENCE) {
stat(
&matches.value_of(options::sources::REFERENCE).unwrap()[..],
matches.value_of(options::sources::REFERENCE).unwrap(),
!matches.is_present(options::NO_DEREF),
)
} else if matches.is_present(options::sources::DATE)
@ -261,7 +262,27 @@ fn parse_timestamp(s: &str) -> FileTime {
};
match time::strptime(&ts, format) {
Ok(tm) => local_tm_to_filetime(to_local(tm)),
Ok(tm) => {
let mut local = to_local(tm);
local.tm_isdst = -1;
let ft = local_tm_to_filetime(local);
// We have to check that ft is valid time. Due to daylight saving
// time switch, local time can jump from 1:59 AM to 3:00 AM,
// in which case any time between 2:00 AM and 2:59 AM is not valid.
// Convert back to local time and see if we got the same value back.
let ts = time::Timespec {
sec: ft.unix_seconds(),
nsec: 0,
};
let tm2 = time::at(ts);
if tm.tm_hour != tm2.tm_hour {
show_error!("invalid date format {}", s);
process::exit(1);
}
ft
}
Err(e) => panic!("Unable to parse timestamp\n{}", e),
}
}

View file

@ -24,7 +24,7 @@ use std::ops::RangeInclusive;
fn parse_sequence(s: &str) -> (char, usize) {
let c = s.chars().next().expect("invalid escape: empty string");
if '0' <= c && c <= '7' {
if ('0'..='7').contains(&c) {
let mut v = c.to_digit(8).unwrap();
let mut consumed = 1;
let bits_per_digit = 3;

View file

@ -16,8 +16,8 @@ use std::io::{stdin, BufRead, BufReader, Read};
use std::path::Path;
static VERSION: &str = env!("CARGO_PKG_VERSION");
static SUMMARY: &str = "Topological sort the strings in FILE.
Strings are defined as any sequence of tokens separated by whitespace (tab, space, or newline).
static SUMMARY: &str = "Topological sort the strings in FILE.
Strings are defined as any sequence of tokens separated by whitespace (tab, space, or newline).
If FILE is not passed in, stdin is used instead.";
static USAGE: &str = "tsort [OPTIONS] FILE";
@ -32,13 +32,16 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
.version(VERSION)
.usage(USAGE)
.about(SUMMARY)
.arg(Arg::with_name(options::FILE).hidden(true))
.arg(
Arg::with_name(options::FILE)
.default_value("-")
.hidden(true),
)
.get_matches_from(args);
let input = match matches.value_of(options::FILE) {
Some(v) => v,
None => "-",
};
let input = matches
.value_of(options::FILE)
.expect("Value is required by clap");
let mut stdin_buf;
let mut file_buf;

View file

@ -65,9 +65,9 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
}
}
return if is_stdin_interactive() {
if is_stdin_interactive() {
libc::EXIT_SUCCESS
} else {
libc::EXIT_FAILURE
};
}
}

View file

@ -149,10 +149,8 @@ fn next_tabstop(tabstops: &[usize], col: usize) -> Option<usize> {
Some(tabstops[0] - col % tabstops[0])
} else {
// find next larger tab
match tabstops.iter().find(|&&t| t > col) {
Some(t) => Some(t - col),
None => None, // if there isn't one in the list, tab becomes a single space
}
// if there isn't one in the list, tab becomes a single space
tabstops.iter().find(|&&t| t > col).map(|t| t-col)
}
}

View file

@ -72,30 +72,27 @@ pub(crate) fn count_bytes_fast<T: WordCountable>(handle: &mut T) -> WcResult<usi
#[cfg(unix)]
{
let fd = handle.as_raw_fd();
match fstat(fd) {
Ok(stat) => {
// If the file is regular, then the `st_size` should hold
// the file's size in bytes.
if (stat.st_mode & S_IFREG) != 0 {
return Ok(stat.st_size as usize);
}
#[cfg(any(target_os = "linux", target_os = "android"))]
{
// Else, if we're on Linux and our file is a FIFO pipe
// (or stdin), we use splice to count the number of bytes.
if (stat.st_mode & S_IFIFO) != 0 {
if let Ok(n) = count_bytes_using_splice(fd) {
return Ok(n);
}
if let Ok(stat) = fstat(fd) {
// If the file is regular, then the `st_size` should hold
// the file's size in bytes.
if (stat.st_mode & S_IFREG) != 0 {
return Ok(stat.st_size as usize);
}
#[cfg(any(target_os = "linux", target_os = "android"))]
{
// Else, if we're on Linux and our file is a FIFO pipe
// (or stdin), we use splice to count the number of bytes.
if (stat.st_mode & S_IFIFO) != 0 {
if let Ok(n) = count_bytes_using_splice(fd) {
return Ok(n);
}
}
}
_ => {}
}
}
// Fall back on `read`, but without the overhead of counting words and lines.
let mut buf = [0 as u8; BUF_SIZE];
let mut buf = [0_u8; BUF_SIZE];
let mut byte_count = 0;
loop {
match handle.read(&mut buf) {

View file

@ -138,11 +138,8 @@ impl AddAssign for WordCount {
}
impl WordCount {
fn with_title<'a>(self, title: &'a str) -> TitledWordCount<'a> {
return TitledWordCount {
title: title,
count: self,
};
fn with_title(self, title: &str) -> TitledWordCount {
TitledWordCount { title, count: self }
}
}
@ -251,7 +248,7 @@ fn is_word_separator(byte: u8) -> bool {
fn word_count_from_reader<T: WordCountable>(
mut reader: T,
settings: &Settings,
path: &String,
path: &str,
) -> WcResult<WordCount> {
let only_count_bytes = settings.show_bytes
&& (!(settings.show_chars
@ -333,18 +330,18 @@ fn word_count_from_reader<T: WordCountable>(
})
}
fn word_count_from_path(path: &String, settings: &Settings) -> WcResult<WordCount> {
fn word_count_from_path(path: &str, settings: &Settings) -> WcResult<WordCount> {
if path == "-" {
let stdin = io::stdin();
let stdin_lock = stdin.lock();
return Ok(word_count_from_reader(stdin_lock, settings, path)?);
word_count_from_reader(stdin_lock, settings, path)
} else {
let path_obj = Path::new(path);
if path_obj.is_dir() {
return Err(WcError::IsDirectory(path.clone()));
Err(WcError::IsDirectory(path.to_owned()))
} else {
let file = File::open(path)?;
return Ok(word_count_from_reader(file, settings, path)?);
word_count_from_reader(file, settings, path)
}
}
}
@ -425,7 +422,7 @@ fn print_stats(
}
if result.title == "-" {
writeln!(stdout_lock, "")?;
writeln!(stdout_lock)?;
} else {
writeln!(stdout_lock, " {}", result.title)?;
}

View file

@ -222,7 +222,6 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
need_runlevel,
need_users,
my_line_only,
has_records: false,
args: matches.free,
};
@ -247,7 +246,6 @@ struct Who {
need_runlevel: bool,
need_users: bool,
my_line_only: bool,
has_records: bool,
args: Vec<String>,
}
@ -321,8 +319,7 @@ impl Who {
println!("{}", users.join(" "));
println!("# users={}", users.len());
} else {
let mut records = Utmpx::iter_all_records().read_from(f).peekable();
self.has_records = records.peek().is_some();
let records = Utmpx::iter_all_records().read_from(f).peekable();
if self.include_heading {
self.print_heading()

View file

@ -31,9 +31,9 @@ fn chgrp<P: AsRef<Path>>(path: P, dgid: gid_t, follow: bool) -> IOResult<()> {
let s = CString::new(path.as_os_str().as_bytes()).unwrap();
let ret = unsafe {
if follow {
libc::chown(s.as_ptr(), (0 as gid_t).wrapping_sub(1), dgid)
libc::chown(s.as_ptr(), 0_u32.wrapping_sub(1), dgid)
} else {
lchown(s.as_ptr(), (0 as gid_t).wrapping_sub(1), dgid)
lchown(s.as_ptr(), 0_u32.wrapping_sub(1), dgid)
}
};
if ret == 0 {

View file

@ -31,6 +31,14 @@ macro_rules! show_error(
);
/// Show a warning to stderr in a silimar style to GNU coreutils.
#[macro_export]
macro_rules! show_error_custom_description (
($err:expr,$($args:tt)+) => ({
eprint!("{}: {}: ", executable!(), $err);
eprintln!($($args)+);
})
);
#[macro_export]
macro_rules! show_warning(
($($args:tt)+) => ({

View file

@ -2,17 +2,13 @@ use crate::common::util::*;
#[test]
fn test_arch() {
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd.run();
assert!(result.success);
new_ucmd!().succeeds();
}
#[test]
fn test_arch_help() {
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd.arg("--help").run();
assert!(result.success);
assert!(result.stdout.contains("architecture name"));
new_ucmd!()
.arg("--help")
.succeeds()
.stdout_contains("architecture name");
}

View file

@ -66,7 +66,7 @@ fn test_zero_param() {
}
fn expect_error(input: Vec<&str>) {
assert!(new_ucmd!().args(&input).fails().no_stdout().stderr.len() > 0);
assert!(new_ucmd!().args(&input).fails().no_stdout().stderr().len() > 0);
}
#[test]

View file

@ -26,6 +26,7 @@ fn test_no_options() {
}
#[test]
#[cfg(unix)]
fn test_no_options_big_input() {
for &n in &[
0,
@ -108,6 +109,7 @@ fn test_directory_and_file() {
}
#[test]
#[cfg(unix)]
fn test_three_directories_and_file_and_stdin() {
let s = TestScenario::new(util_name!());
s.fixtures.mkdir("test_directory3");

View file

@ -149,7 +149,7 @@ fn test_big_h() {
.arg("bin")
.arg("/proc/self/fd")
.fails()
.stderr
.stderr_str()
.lines()
.fold(0, |acc, _| acc + 1)
> 1

View file

@ -48,7 +48,7 @@ fn run_single_test(test: &TestCase, at: AtPath, mut ucmd: UCommand) {
}
let r = ucmd.run();
if !r.success {
println!("{}", r.stderr);
println!("{}", r.stderr_str());
panic!("{:?}: failed", ucmd.raw);
}
@ -297,13 +297,14 @@ fn test_chmod_recursive() {
mkfile(&at.plus_as_string("a/b/c/c"), 0o100444);
mkfile(&at.plus_as_string("z/y"), 0o100444);
let result = ucmd
.arg("-R")
ucmd.arg("-R")
.arg("--verbose")
.arg("-r,a+w")
.arg("a")
.arg("z")
.succeeds();
.succeeds()
.stderr_contains(&"to 333 (-wx-wx-wx)")
.stderr_contains(&"to 222 (-w--w--w-)");
assert_eq!(at.metadata("z/y").permissions().mode(), 0o100222);
assert_eq!(at.metadata("a/a").permissions().mode(), 0o100222);
@ -312,8 +313,6 @@ fn test_chmod_recursive() {
println!("mode {:o}", at.metadata("a").permissions().mode());
assert_eq!(at.metadata("a").permissions().mode(), 0o40333);
assert_eq!(at.metadata("z").permissions().mode(), 0o40333);
assert!(result.stderr.contains("to 333 (-wx-wx-wx)"));
assert!(result.stderr.contains("to 222 (-w--w--w-)"));
unsafe {
umask(original_umask);
@ -322,30 +321,24 @@ fn test_chmod_recursive() {
#[test]
fn test_chmod_non_existing_file() {
let (_at, mut ucmd) = at_and_ucmd!();
let result = ucmd
new_ucmd!()
.arg("-R")
.arg("--verbose")
.arg("-r,a+w")
.arg("dont-exist")
.fails();
assert!(result
.stderr
.contains("cannot access 'dont-exist': No such file or directory"));
.fails()
.stderr_contains(&"cannot access 'dont-exist': No such file or directory");
}
#[test]
fn test_chmod_preserve_root() {
let (_at, mut ucmd) = at_and_ucmd!();
let result = ucmd
new_ucmd!()
.arg("-R")
.arg("--preserve-root")
.arg("755")
.arg("/")
.fails();
assert!(result
.stderr
.contains("chmod: error: it is dangerous to operate recursively on '/'"));
.fails()
.stderr_contains(&"chmod: error: it is dangerous to operate recursively on '/'");
}
#[test]
@ -362,33 +355,27 @@ fn test_chmod_symlink_non_existing_file() {
let expected_stderr = &format!("cannot operate on dangling symlink '{}'", test_symlink);
at.symlink_file(non_existing, test_symlink);
let mut result;
// this cannot succeed since the symbolic link dangles
result = scene.ucmd().arg("755").arg("-v").arg(test_symlink).fails();
println!("stdout = {:?}", result.stdout);
println!("stderr = {:?}", result.stderr);
assert!(result.stdout.contains(expected_stdout));
assert!(result.stderr.contains(expected_stderr));
assert_eq!(result.code, Some(1));
scene.ucmd()
.arg("755")
.arg("-v")
.arg(test_symlink)
.fails()
.code_is(1)
.stdout_contains(expected_stdout)
.stderr_contains(expected_stderr);
// this should be the same than with just '-v' but without stderr
result = scene
.ucmd()
scene.ucmd()
.arg("755")
.arg("-v")
.arg("-f")
.arg(test_symlink)
.fails();
println!("stdout = {:?}", result.stdout);
println!("stderr = {:?}", result.stderr);
assert!(result.stdout.contains(expected_stdout));
assert!(result.stderr.is_empty());
assert_eq!(result.code, Some(1));
.run()
.code_is(1)
.no_stderr()
.stdout_contains(expected_stdout);
}
#[test]
@ -405,18 +392,15 @@ fn test_chmod_symlink_non_existing_file_recursive() {
non_existing,
&format!("{}/{}", test_directory, test_symlink),
);
let mut result;
// this should succeed
result = scene
.ucmd()
scene.ucmd()
.arg("-R")
.arg("755")
.arg(test_directory)
.succeeds();
assert_eq!(result.code, Some(0));
assert!(result.stdout.is_empty());
assert!(result.stderr.is_empty());
.succeeds()
.no_stderr()
.no_stdout();
let expected_stdout = &format!(
"mode of '{}' retained as 0755 (rwxr-xr-x)\nneither symbolic link '{}/{}' nor referent has been changed",
@ -424,37 +408,25 @@ fn test_chmod_symlink_non_existing_file_recursive() {
);
// '-v': this should succeed without stderr
result = scene
.ucmd()
scene.ucmd()
.arg("-R")
.arg("-v")
.arg("755")
.arg(test_directory)
.succeeds();
println!("stdout = {:?}", result.stdout);
println!("stderr = {:?}", result.stderr);
assert!(result.stdout.contains(expected_stdout));
assert!(result.stderr.is_empty());
assert_eq!(result.code, Some(0));
.succeeds()
.stdout_contains(expected_stdout)
.no_stderr();
// '-vf': this should be the same than with just '-v'
result = scene
.ucmd()
scene.ucmd()
.arg("-R")
.arg("-v")
.arg("-f")
.arg("755")
.arg(test_directory)
.succeeds();
println!("stdout = {:?}", result.stdout);
println!("stderr = {:?}", result.stderr);
assert!(result.stdout.contains(expected_stdout));
assert!(result.stderr.is_empty());
assert_eq!(result.code, Some(0));
.succeeds()
.stdout_contains(expected_stdout)
.no_stderr();
}
#[test]

View file

@ -64,14 +64,14 @@ fn test_preference_of_userspec() {
// As seems to be a configuration issue, ignoring it
return;
}
println!("result.stdout {}", result.stdout);
println!("result.stderr = {}", result.stderr);
let username = result.stdout.trim_end();
println!("result.stdout = {}", result.stdout_str());
println!("result.stderr = {}", result.stderr_str());
let username = result.stdout_str().trim_end();
let ts = TestScenario::new("id");
let result = ts.cmd("id").arg("-g").arg("-n").run();
println!("result.stdout {}", result.stdout);
println!("result.stderr = {}", result.stderr);
println!("result.stdout = {}", result.stdout_str());
println!("result.stderr = {}", result.stderr_str());
if is_ci() && result.stderr.contains("cannot find name for user ID") {
// In the CI, some server are failing to return id.
@ -79,7 +79,7 @@ fn test_preference_of_userspec() {
return;
}
let group_name = result.stdout.trim_end();
let group_name = result.stdout_str().trim_end();
let (at, mut ucmd) = at_and_ucmd!();
at.mkdir("a");
@ -93,6 +93,6 @@ fn test_preference_of_userspec() {
.arg(format!("--userspec={}:{}", username, group_name))
.run();
println!("result.stdout {}", result.stdout);
println!("result.stderr = {}", result.stderr);
println!("result.stdout = {}", result.stdout_str());
println!("result.stderr = {}", result.stderr_str());
}

View file

@ -35,14 +35,19 @@ fn test_empty() {
}
#[test]
#[ignore]
fn test_arg_overrides_stdin() {
let (at, mut ucmd) = at_and_ucmd!();
let input = "foobarfoobar";
at.touch("a");
let result = ucmd.arg("a").pipe_in(input.as_bytes()).run();
let result = ucmd
.arg("a")
.pipe_in(input.as_bytes())
// the command might have exited before all bytes have been pipe in.
// in that case, we don't care about the error (broken pipe)
.ignore_stdin_write_error()
.run();
println!("{}, {}", result.stdout, result.stderr);

View file

@ -275,8 +275,8 @@ fn test_cp_arg_no_clobber_twice() {
.arg("dest.txt")
.run();
println!("stderr = {:?}", result.stderr);
println!("stdout = {:?}", result.stdout);
println!("stderr = {:?}", result.stderr_str());
println!("stdout = {:?}", result.stdout_str());
assert!(result.success);
assert!(result.stderr.is_empty());
assert_eq!(at.read("source.txt"), "");
@ -317,8 +317,8 @@ fn test_cp_arg_force() {
.arg(TEST_HELLO_WORLD_DEST)
.run();
println!("{:?}", result.stderr);
println!("{:?}", result.stdout);
println!("{:?}", result.stderr_str());
println!("{:?}", result.stdout_str());
assert!(result.success);
assert_eq!(at.read(TEST_HELLO_WORLD_DEST), "Hello, World!\n");
@ -602,7 +602,7 @@ fn test_cp_deref_folder_to_folder() {
.arg(TEST_COPY_FROM_FOLDER)
.arg(TEST_COPY_TO_FOLDER_NEW)
.run();
println!("cp output {}", result.stdout);
println!("cp output {}", result.stdout_str());
// Check that the exit code represents a successful copy.
assert!(result.success);
@ -611,12 +611,12 @@ fn test_cp_deref_folder_to_folder() {
{
let scene2 = TestScenario::new("ls");
let result = scene2.cmd("ls").arg("-al").arg(path_to_new_symlink).run();
println!("ls source {}", result.stdout);
println!("ls source {}", result.stdout_str());
let path_to_new_symlink = at.subdir.join(TEST_COPY_TO_FOLDER_NEW);
let result = scene2.cmd("ls").arg("-al").arg(path_to_new_symlink).run();
println!("ls dest {}", result.stdout);
println!("ls dest {}", result.stdout_str());
}
#[cfg(windows)]
@ -706,7 +706,7 @@ fn test_cp_no_deref_folder_to_folder() {
.arg(TEST_COPY_FROM_FOLDER)
.arg(TEST_COPY_TO_FOLDER_NEW)
.run();
println!("cp output {}", result.stdout);
println!("cp output {}", result.stdout_str());
// Check that the exit code represents a successful copy.
assert!(result.success);
@ -715,12 +715,12 @@ fn test_cp_no_deref_folder_to_folder() {
{
let scene2 = TestScenario::new("ls");
let result = scene2.cmd("ls").arg("-al").arg(path_to_new_symlink).run();
println!("ls source {}", result.stdout);
println!("ls source {}", result.stdout_str());
let path_to_new_symlink = at.subdir.join(TEST_COPY_TO_FOLDER_NEW);
let result = scene2.cmd("ls").arg("-al").arg(path_to_new_symlink).run();
println!("ls dest {}", result.stdout);
println!("ls dest {}", result.stdout_str());
}
#[cfg(windows)]
@ -809,7 +809,7 @@ fn test_cp_archive() {
let scene2 = TestScenario::new("ls");
let result = scene2.cmd("ls").arg("-al").arg(at.subdir).run();
println!("ls dest {}", result.stdout);
println!("ls dest {}", result.stdout_str());
assert_eq!(creation, creation2);
assert!(result.success);
}
@ -863,7 +863,7 @@ fn test_cp_archive_recursive() {
.arg(&at.subdir.join(TEST_COPY_TO_FOLDER))
.run();
println!("ls dest {}", result.stdout);
println!("ls dest {}", result.stdout_str());
let scene2 = TestScenario::new("ls");
let result = scene2
@ -872,7 +872,7 @@ fn test_cp_archive_recursive() {
.arg(&at.subdir.join(TEST_COPY_TO_FOLDER_NEW))
.run();
println!("ls dest {}", result.stdout);
println!("ls dest {}", result.stdout_str());
assert!(at.file_exists(
&at.subdir
.join(TEST_COPY_TO_FOLDER_NEW)
@ -946,7 +946,7 @@ fn test_cp_preserve_timestamps() {
let scene2 = TestScenario::new("ls");
let result = scene2.cmd("ls").arg("-al").arg(at.subdir).run();
println!("ls dest {}", result.stdout);
println!("ls dest {}", result.stdout_str());
assert_eq!(creation, creation2);
assert!(result.success);
}
@ -984,7 +984,7 @@ fn test_cp_dont_preserve_timestamps() {
let scene2 = TestScenario::new("ls");
let result = scene2.cmd("ls").arg("-al").arg(at.subdir).run();
println!("ls dest {}", result.stdout);
println!("ls dest {}", result.stdout_str());
println!("creation {:?} / {:?}", creation, creation2);
assert_ne!(creation, creation2);

View file

@ -28,13 +28,13 @@ fn test_date_rfc_3339() {
// Check that the output matches the regexp
let rfc_regexp = r"(\d+)-(0[1-9]|1[012])-(0[1-9]|[12]\d|3[01])\s([01]\d|2[0-3]):([0-5]\d):([0-5]\d|60)(\.\d+)?(([Zz])|([\+|\-]([01]\d|2[0-3])))";
let re = Regex::new(rfc_regexp).unwrap();
assert!(re.is_match(&result.stdout.trim()));
assert!(re.is_match(&result.stdout_str().trim()));
result = scene.ucmd().arg("--rfc-3339=seconds").succeeds();
// Check that the output matches the regexp
let re = Regex::new(rfc_regexp).unwrap();
assert!(re.is_match(&result.stdout.trim()));
assert!(re.is_match(&result.stdout_str().trim()));
}
#[test]
@ -73,13 +73,13 @@ fn test_date_format_y() {
assert!(result.success);
let mut re = Regex::new(r"^\d{4}$").unwrap();
assert!(re.is_match(&result.stdout.trim()));
assert!(re.is_match(&result.stdout_str().trim()));
result = scene.ucmd().arg("+%y").succeeds();
assert!(result.success);
re = Regex::new(r"^\d{2}$").unwrap();
assert!(re.is_match(&result.stdout.trim()));
assert!(re.is_match(&result.stdout_str().trim()));
}
#[test]
@ -90,13 +90,13 @@ fn test_date_format_m() {
assert!(result.success);
let mut re = Regex::new(r"\S+").unwrap();
assert!(re.is_match(&result.stdout.trim()));
assert!(re.is_match(&result.stdout_str().trim()));
result = scene.ucmd().arg("+%m").succeeds();
assert!(result.success);
re = Regex::new(r"^\d{2}$").unwrap();
assert!(re.is_match(&result.stdout.trim()));
assert!(re.is_match(&result.stdout_str().trim()));
}
#[test]
@ -107,20 +107,20 @@ fn test_date_format_day() {
assert!(result.success);
let mut re = Regex::new(r"\S+").unwrap();
assert!(re.is_match(&result.stdout.trim()));
assert!(re.is_match(&result.stdout_str().trim()));
result = scene.ucmd().arg("+%A").succeeds();
assert!(result.success);
re = Regex::new(r"\S+").unwrap();
assert!(re.is_match(&result.stdout.trim()));
assert!(re.is_match(&result.stdout_str().trim()));
result = scene.ucmd().arg("+%u").succeeds();
assert!(result.success);
re = Regex::new(r"^\d{1}$").unwrap();
assert!(re.is_match(&result.stdout.trim()));
assert!(re.is_match(&result.stdout_str().trim()));
}
#[test]
@ -131,7 +131,7 @@ fn test_date_format_full_day() {
assert!(result.success);
let re = Regex::new(r"\S+ \d{4}-\d{2}-\d{2}").unwrap();
assert!(re.is_match(&result.stdout.trim()));
assert!(re.is_match(&result.stdout_str().trim()));
}
#[test]

View file

@ -7,10 +7,9 @@ const SUB_LINK: &str = "subdir/links/sublink.txt";
#[test]
fn test_du_basics() {
let (_at, mut ucmd) = at_and_ucmd!();
let result = ucmd.run();
assert!(result.success);
assert_eq!(result.stderr, "");
new_ucmd!()
.succeeds()
.no_stderr();
}
#[cfg(target_vendor = "apple")]
fn _du_basics(s: String) {
@ -22,7 +21,7 @@ fn _du_basics(s: String) {
assert_eq!(s, answer);
}
#[cfg(not(target_vendor = "apple"))]
fn _du_basics(s: String) {
fn _du_basics(s: &str) {
let answer = "28\t./subdir
8\t./subdir/deeper
16\t./subdir/links
@ -38,19 +37,19 @@ fn test_du_basics_subdir() {
let result = ucmd.arg(SUB_DIR).run();
assert!(result.success);
assert_eq!(result.stderr, "");
_du_basics_subdir(result.stdout);
_du_basics_subdir(result.stdout_str());
}
#[cfg(target_vendor = "apple")]
fn _du_basics_subdir(s: String) {
fn _du_basics_subdir(s: &str) {
assert_eq!(s, "4\tsubdir/deeper\n");
}
#[cfg(target_os = "windows")]
fn _du_basics_subdir(s: String) {
fn _du_basics_subdir(s: &str) {
assert_eq!(s, "0\tsubdir/deeper\n");
}
#[cfg(all(not(target_vendor = "apple"), not(target_os = "windows")))]
fn _du_basics_subdir(s: String) {
fn _du_basics_subdir(s: &str) {
// MS-WSL linux has altered expected output
if !is_wsl() {
assert_eq!(s, "8\tsubdir/deeper\n");
@ -64,7 +63,7 @@ fn test_du_basics_bad_name() {
let (_at, mut ucmd) = at_and_ucmd!();
let result = ucmd.arg("bad_name").run();
assert_eq!(result.stdout, "");
assert_eq!(result.stdout_str(), "");
assert_eq!(
result.stderr,
"du: error: bad_name: No such file or directory\n"
@ -81,20 +80,20 @@ fn test_du_soft_link() {
let result = ts.ucmd().arg(SUB_DIR_LINKS).run();
assert!(result.success);
assert_eq!(result.stderr, "");
_du_soft_link(result.stdout);
_du_soft_link(result.stdout_str());
}
#[cfg(target_vendor = "apple")]
fn _du_soft_link(s: String) {
fn _du_soft_link(s: &str) {
// 'macos' host variants may have `du` output variation for soft links
assert!((s == "12\tsubdir/links\n") || (s == "16\tsubdir/links\n"));
}
#[cfg(target_os = "windows")]
fn _du_soft_link(s: String) {
fn _du_soft_link(s: &str) {
assert_eq!(s, "8\tsubdir/links\n");
}
#[cfg(all(not(target_vendor = "apple"), not(target_os = "windows")))]
fn _du_soft_link(s: String) {
fn _du_soft_link(s: &str) {
// MS-WSL linux has altered expected output
if !is_wsl() {
assert_eq!(s, "16\tsubdir/links\n");
@ -114,19 +113,19 @@ fn test_du_hard_link() {
assert!(result.success);
assert_eq!(result.stderr, "");
// We do not double count hard links as the inodes are identical
_du_hard_link(result.stdout);
_du_hard_link(result.stdout_str());
}
#[cfg(target_vendor = "apple")]
fn _du_hard_link(s: String) {
fn _du_hard_link(s: &str) {
assert_eq!(s, "12\tsubdir/links\n")
}
#[cfg(target_os = "windows")]
fn _du_hard_link(s: String) {
fn _du_hard_link(s: &str) {
assert_eq!(s, "8\tsubdir/links\n")
}
#[cfg(all(not(target_vendor = "apple"), not(target_os = "windows")))]
fn _du_hard_link(s: String) {
fn _du_hard_link(s: &str) {
// MS-WSL linux has altered expected output
if !is_wsl() {
assert_eq!(s, "16\tsubdir/links\n");
@ -142,19 +141,19 @@ fn test_du_d_flag() {
let result = ts.ucmd().arg("-d").arg("1").run();
assert!(result.success);
assert_eq!(result.stderr, "");
_du_d_flag(result.stdout);
_du_d_flag(result.stdout_str());
}
#[cfg(target_vendor = "apple")]
fn _du_d_flag(s: String) {
fn _du_d_flag(s: &str) {
assert_eq!(s, "16\t./subdir\n20\t./\n");
}
#[cfg(target_os = "windows")]
fn _du_d_flag(s: String) {
fn _du_d_flag(s: &str) {
assert_eq!(s, "8\t./subdir\n8\t./\n");
}
#[cfg(all(not(target_vendor = "apple"), not(target_os = "windows")))]
fn _du_d_flag(s: String) {
fn _du_d_flag(s: &str) {
// MS-WSL linux has altered expected output
if !is_wsl() {
assert_eq!(s, "28\t./subdir\n36\t./\n");
@ -167,10 +166,11 @@ fn _du_d_flag(s: String) {
fn test_du_h_flag_empty_file() {
let ts = TestScenario::new("du");
let result = ts.ucmd().arg("-h").arg("empty.txt").run();
assert!(result.success);
assert_eq!(result.stderr, "");
assert_eq!(result.stdout, "0\tempty.txt\n");
ts.ucmd()
.arg("-h")
.arg("empty.txt")
.succeeds()
.stdout_only("0\tempty.txt\n");
}
#[cfg(feature = "touch")]
@ -190,3 +190,33 @@ fn test_du_time() {
assert_eq!(result.stderr, "");
assert_eq!(result.stdout, "0\t2015-05-15 00:00\tdate_test\n");
}
#[cfg(not(target_os = "windows"))]
#[cfg(feature = "chmod")]
#[test]
fn test_du_no_permission() {
let ts = TestScenario::new("du");
let chmod = ts.ccmd("chmod").arg("-r").arg(SUB_DIR_LINKS).run();
println!("chmod output: {:?}", chmod);
assert!(chmod.success);
let result = ts.ucmd().arg(SUB_DIR_LINKS).run();
ts.ccmd("chmod").arg("+r").arg(SUB_DIR_LINKS).run();
assert!(result.success);
assert_eq!(
result.stderr,
"du: cannot read directory subdir/links: Permission denied (os error 13)\n"
);
_du_no_permission(result.stdout);
}
#[cfg(target_vendor = "apple")]
fn _du_no_permission(s: String) {
assert_eq!(s, "0\tsubdir/links\n");
}
#[cfg(all(not(target_vendor = "apple"), not(target_os = "windows")))]
fn _du_no_permission(s: String) {
assert_eq!(s, "4\tsubdir/links\n");
}

View file

@ -2,22 +2,20 @@ use crate::common::util::*;
#[test]
fn test_default() {
//CmdResult.stdout_only(...) trims trailing newlines
assert_eq!("hi\n", new_ucmd!().arg("hi").succeeds().no_stderr().stdout);
new_ucmd!()
.arg("hi")
.succeeds()
.stdout_only("hi\n");
}
#[test]
fn test_no_trailing_newline() {
//CmdResult.stdout_only(...) trims trailing newlines
assert_eq!(
"hi",
new_ucmd!()
.arg("-n")
.arg("hi")
.succeeds()
.no_stderr()
.stdout
);
new_ucmd!()
.arg("-n")
.arg("hi")
.succeeds()
.no_stderr()
.stdout_only("hi");
}
#[test]
@ -192,39 +190,38 @@ fn test_hyphen_values_inside_string() {
new_ucmd!()
.arg("'\"\n'CXXFLAGS=-g -O2'\n\"'")
.succeeds()
.stdout
.contains("CXXFLAGS");
.stdout_contains("CXXFLAGS");
}
#[test]
fn test_hyphen_values_at_start() {
let result = new_ucmd!()
new_ucmd!()
.arg("-E")
.arg("-test")
.arg("araba")
.arg("-merci")
.run();
assert!(result.success);
assert_eq!(false, result.stdout.contains("-E"));
assert_eq!(result.stdout, "-test araba -merci\n");
.run()
.success()
.stdout_does_not_contain("-E")
.stdout_is("-test araba -merci\n");
}
#[test]
fn test_hyphen_values_between() {
let result = new_ucmd!().arg("test").arg("-E").arg("araba").run();
new_ucmd!()
.arg("test")
.arg("-E")
.arg("araba")
.run()
.success()
.stdout_is("test -E araba\n");
assert!(result.success);
assert_eq!(result.stdout, "test -E araba\n");
let result = new_ucmd!()
new_ucmd!()
.arg("dumdum ")
.arg("dum dum dum")
.arg("-e")
.arg("dum")
.run();
assert!(result.success);
assert_eq!(result.stdout, "dumdum dum dum dum -e dum\n");
assert_eq!(true, result.stdout.contains("-e"));
.run()
.success()
.stdout_is("dumdum dum dum dum -e dum\n");
}

View file

@ -8,45 +8,35 @@ use tempfile::tempdir;
#[test]
fn test_env_help() {
assert!(new_ucmd!()
new_ucmd!()
.arg("--help")
.succeeds()
.no_stderr()
.stdout
.contains("OPTIONS:"));
.stdout_contains("OPTIONS:");
}
#[test]
fn test_env_version() {
assert!(new_ucmd!()
new_ucmd!()
.arg("--version")
.succeeds()
.no_stderr()
.stdout
.contains(util_name!()));
.stdout_contains(util_name!());
}
#[test]
fn test_echo() {
// assert!(new_ucmd!().arg("printf").arg("FOO-bar").succeeds().no_stderr().stdout.contains("FOO-bar"));
let mut cmd = new_ucmd!();
cmd.arg("echo").arg("FOO-bar");
println!("cmd={:?}", cmd);
let result = new_ucmd!()
.arg("echo")
.arg("FOO-bar")
.succeeds();
let result = cmd.run();
println!("success={:?}", result.success);
println!("stdout={:?}", result.stdout);
println!("stderr={:?}", result.stderr);
assert!(result.success);
let out = result.stdout.trim_end();
assert_eq!(out, "FOO-bar");
assert_eq!(result.stdout_str().trim(), "FOO-bar");
}
#[test]
fn test_file_option() {
let out = new_ucmd!().arg("-f").arg("vars.conf.txt").run().stdout;
let out = new_ucmd!().arg("-f").arg("vars.conf.txt").run().stdout_move_str();
assert_eq!(
out.lines()
@ -63,7 +53,7 @@ fn test_combined_file_set() {
.arg("vars.conf.txt")
.arg("FOO=bar.alt")
.run()
.stdout;
.stdout_move_str();
assert_eq!(out.lines().filter(|&line| line == "FOO=bar.alt").count(), 1);
}
@ -76,8 +66,8 @@ fn test_combined_file_set_unset() {
.arg("-f")
.arg("vars.conf.txt")
.arg("FOO=bar.alt")
.run()
.stdout;
.succeeds()
.stdout_move_str();
assert_eq!(
out.lines()
@ -89,17 +79,17 @@ fn test_combined_file_set_unset() {
#[test]
fn test_single_name_value_pair() {
let out = new_ucmd!().arg("FOO=bar").run().stdout;
let out = new_ucmd!().arg("FOO=bar").run();
assert!(out.lines().any(|line| line == "FOO=bar"));
assert!(out.stdout_str().lines().any(|line| line == "FOO=bar"));
}
#[test]
fn test_multiple_name_value_pairs() {
let out = new_ucmd!().arg("FOO=bar").arg("ABC=xyz").run().stdout;
let out = new_ucmd!().arg("FOO=bar").arg("ABC=xyz").run();
assert_eq!(
out.lines()
out.stdout_str().lines()
.filter(|&line| line == "FOO=bar" || line == "ABC=xyz")
.count(),
2
@ -110,13 +100,8 @@ fn test_multiple_name_value_pairs() {
fn test_ignore_environment() {
let scene = TestScenario::new(util_name!());
let out = scene.ucmd().arg("-i").run().stdout;
assert_eq!(out, "");
let out = scene.ucmd().arg("-").run().stdout;
assert_eq!(out, "");
scene.ucmd().arg("-i").run().no_stdout();
scene.ucmd().arg("-").run().no_stdout();
}
#[test]
@ -126,8 +111,8 @@ fn test_null_delimiter() {
.arg("--null")
.arg("FOO=bar")
.arg("ABC=xyz")
.run()
.stdout;
.succeeds()
.stdout_move_str();
let mut vars: Vec<_> = out.split('\0').collect();
assert_eq!(vars.len(), 3);
@ -145,8 +130,8 @@ fn test_unset_variable() {
.ucmd_keepenv()
.arg("-u")
.arg("HOME")
.run()
.stdout;
.succeeds()
.stdout_move_str();
assert_eq!(out.lines().any(|line| line.starts_with("HOME=")), false);
}
@ -173,8 +158,8 @@ fn test_change_directory() {
.arg("--chdir")
.arg(&temporary_path)
.arg(pwd)
.run()
.stdout;
.succeeds()
.stdout_move_str();
assert_eq!(out.trim(), temporary_path.as_os_str())
}
@ -193,8 +178,8 @@ fn test_change_directory() {
.ucmd()
.arg("--chdir")
.arg(&temporary_path)
.run()
.stdout;
.succeeds()
.stdout_move_str();
assert_eq!(
out.lines()
.any(|line| line.ends_with(temporary_path.file_name().unwrap().to_str().unwrap())),
@ -214,6 +199,6 @@ fn test_fail_change_directory() {
.arg(some_non_existing_path)
.arg("pwd")
.fails()
.stderr;
.stderr_move_str();
assert!(out.contains("env: cannot change directory to "));
}

View file

@ -2,57 +2,54 @@ use crate::common::util::*;
#[test]
fn test_with_tab() {
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd.arg("with-tab.txt").run();
assert!(result.success);
assert!(result.stdout.contains(" "));
assert!(!result.stdout.contains("\t"));
new_ucmd!()
.arg("with-tab.txt")
.succeeds()
.stdout_contains(" ")
.stdout_does_not_contain("\t");
}
#[test]
fn test_with_trailing_tab() {
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd.arg("with-trailing-tab.txt").run();
assert!(result.success);
assert!(result.stdout.contains("with tabs=> "));
assert!(!result.stdout.contains("\t"));
new_ucmd!()
.arg("with-trailing-tab.txt")
.succeeds()
.stdout_contains("with tabs=> ")
.stdout_does_not_contain("\t");
}
#[test]
fn test_with_trailing_tab_i() {
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd.arg("with-trailing-tab.txt").arg("-i").run();
assert!(result.success);
assert!(result.stdout.contains(" // with tabs=>\t"));
new_ucmd!()
.arg("with-trailing-tab.txt")
.arg("-i")
.succeeds()
.stdout_contains(" // with tabs=>\t");
}
#[test]
fn test_with_tab_size() {
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd.arg("with-tab.txt").arg("--tabs=10").run();
assert!(result.success);
assert!(result.stdout.contains(" "));
new_ucmd!()
.arg("with-tab.txt")
.arg("--tabs=10")
.succeeds()
.stdout_contains(" ");
}
#[test]
fn test_with_space() {
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd.arg("with-spaces.txt").run();
assert!(result.success);
assert!(result.stdout.contains(" return"));
new_ucmd!()
.arg("with-spaces.txt")
.succeeds()
.stdout_contains(" return");
}
#[test]
fn test_with_multiple_files() {
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd.arg("with-spaces.txt").arg("with-tab.txt").run();
assert!(result.success);
assert!(result.stdout.contains(" return"));
assert!(result.stdout.contains(" "));
new_ucmd!()
.arg("with-spaces.txt")
.arg("with-tab.txt")
.succeeds()
.stdout_contains(" return")
.stdout_contains(" ");
}

View file

@ -32,13 +32,10 @@ fn test_first_100000_integers() {
}
println!("STDIN='{}'", instring);
let result = new_ucmd!().pipe_in(instring.as_bytes()).run();
let stdout = result.stdout;
assert!(result.success);
let result = new_ucmd!().pipe_in(instring.as_bytes()).succeeds();
// `seq 0 100000 | factor | sha1sum` => "4ed2d8403934fa1c76fe4b84c5d4b8850299c359"
let hash_check = sha1::Sha1::from(stdout.as_bytes()).hexdigest();
let hash_check = sha1::Sha1::from(result.stdout()).hexdigest();
assert_eq!(hash_check, "4ed2d8403934fa1c76fe4b84c5d4b8850299c359");
}

View file

@ -5,7 +5,7 @@ fn test_fmt() {
let result = new_ucmd!().arg("one-word-per-line.txt").run();
//.stdout_is_fixture("call_graph.expected");
assert_eq!(
result.stdout.trim(),
result.stdout_str().trim(),
"this is a file with one word per line"
);
}
@ -15,7 +15,7 @@ fn test_fmt_q() {
let result = new_ucmd!().arg("-q").arg("one-word-per-line.txt").run();
//.stdout_is_fixture("call_graph.expected");
assert_eq!(
result.stdout.trim(),
result.stdout_str().trim(),
"this is a file with one word per line"
);
}
@ -42,7 +42,7 @@ fn test_fmt_w() {
.arg("one-word-per-line.txt")
.run();
//.stdout_is_fixture("call_graph.expected");
assert_eq!(result.stdout.trim(), "this is a file with one word per line");
assert_eq!(result.stdout_str().trim(), "this is a file with one word per line");
}

View file

@ -2,26 +2,25 @@ use crate::common::util::*;
#[test]
fn test_groups() {
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd.run();
println!("result.stdout {}", result.stdout);
println!("result.stderr = {}", result.stderr);
if is_ci() && result.stdout.trim().is_empty() {
let result = new_ucmd!().run();
println!("result.stdout = {}", result.stdout_str());
println!("result.stderr = {}", result.stderr_str());
if is_ci() && result.stdout_str().trim().is_empty() {
// In the CI, some server are failing to return the group.
// As seems to be a configuration issue, ignoring it
return;
}
assert!(result.success);
assert!(!result.stdout.trim().is_empty());
assert!(!result.stdout_str().trim().is_empty());
}
#[test]
fn test_groups_arg() {
// get the username with the "id -un" command
let result = TestScenario::new("id").ucmd_keepenv().arg("-un").run();
println!("result.stdout {}", result.stdout);
println!("result.stderr = {}", result.stderr);
let s1 = String::from(result.stdout.trim());
println!("result.stdout = {}", result.stdout_str());
println!("result.stderr = {}", result.stderr_str());
let s1 = String::from(result.stdout_str().trim());
if is_ci() && s1.parse::<f64>().is_ok() {
// In the CI, some server are failing to return id -un.
// So, if we are getting a uid, just skip this test
@ -29,18 +28,18 @@ fn test_groups_arg() {
return;
}
println!("result.stdout {}", result.stdout);
println!("result.stderr = {}", result.stderr);
println!("result.stdout = {}", result.stdout_str());
println!("result.stderr = {}", result.stderr_str());
assert!(result.success);
assert!(!result.stdout.is_empty());
let username = result.stdout.trim();
assert!(!result.stdout_str().is_empty());
let username = result.stdout_str().trim();
// call groups with the user name to check that we
// are getting something
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd.arg(username).run();
println!("result.stdout {}", result.stdout);
println!("result.stderr = {}", result.stderr);
println!("result.stdout = {}", result.stdout_str());
println!("result.stderr = {}", result.stderr_str());
assert!(result.success);
assert!(!result.stdout.is_empty());
assert!(!result.stdout_str().is_empty());
}

View file

@ -17,14 +17,14 @@ macro_rules! test_digest {
fn test_single_file() {
let ts = TestScenario::new("hashsum");
assert_eq!(ts.fixtures.read(EXPECTED_FILE),
get_hash!(ts.ucmd().arg(DIGEST_ARG).arg(BITS_ARG).arg("input.txt").succeeds().no_stderr().stdout));
get_hash!(ts.ucmd().arg(DIGEST_ARG).arg(BITS_ARG).arg("input.txt").succeeds().no_stderr().stdout_str()));
}
#[test]
fn test_stdin() {
let ts = TestScenario::new("hashsum");
assert_eq!(ts.fixtures.read(EXPECTED_FILE),
get_hash!(ts.ucmd().arg(DIGEST_ARG).arg(BITS_ARG).pipe_in_fixture("input.txt").succeeds().no_stderr().stdout));
get_hash!(ts.ucmd().arg(DIGEST_ARG).arg(BITS_ARG).pipe_in_fixture("input.txt").succeeds().no_stderr().stdout_str()));
}
}
)*)

View file

@ -9,5 +9,5 @@ fn test_normal() {
assert!(result.success);
let re = Regex::new(r"^[0-9a-f]{8}").unwrap();
assert!(re.is_match(&result.stdout.trim()));
assert!(re.is_match(&result.stdout_str()));
}

View file

@ -6,8 +6,8 @@ fn test_hostname() {
let ls_short_res = new_ucmd!().arg("-s").succeeds();
let ls_domain_res = new_ucmd!().arg("-d").succeeds();
assert!(ls_default_res.stdout.len() >= ls_short_res.stdout.len());
assert!(ls_default_res.stdout.len() >= ls_domain_res.stdout.len());
assert!(ls_default_res.stdout().len() >= ls_short_res.stdout().len());
assert!(ls_default_res.stdout().len() >= ls_domain_res.stdout().len());
}
// FixME: fails for "MacOS"
@ -17,14 +17,14 @@ fn test_hostname_ip() {
let result = new_ucmd!().arg("-i").run();
println!("{:#?}", result);
assert!(result.success);
assert!(!result.stdout.trim().is_empty());
assert!(!result.stdout_str().trim().is_empty());
}
#[test]
fn test_hostname_full() {
let result = new_ucmd!().arg("-f").succeeds();
assert!(!result.stdout.trim().is_empty());
let ls_short_res = new_ucmd!().arg("-s").succeeds();
assert!(result.stdout.trim().contains(ls_short_res.stdout.trim()));
assert!(!ls_short_res.stdout_str().trim().is_empty());
new_ucmd!().arg("-f").succeeds()
.stdout_contains(ls_short_res.stdout_str().trim());
}

View file

@ -9,33 +9,29 @@ fn return_whoami_username() -> String {
return String::from("");
}
result.stdout.trim().to_string()
result.stdout_str().trim().to_string()
}
#[test]
fn test_id() {
let scene = TestScenario::new(util_name!());
let mut result = scene.ucmd().arg("-u").run();
let result = new_ucmd!().arg("-u").run();
if result.stderr.contains("cannot find name for user ID") {
// In the CI, some server are failing to return whoami.
// As seems to be a configuration issue, ignoring it
return;
}
assert!(result.success);
let uid = String::from(result.stdout.trim());
result = scene.ucmd().run();
let uid = result.success().stdout_str().trim();
let result = new_ucmd!().run();
if is_ci() && result.stderr.contains("cannot find name for user ID") {
// In the CI, some server are failing to return whoami.
// As seems to be a configuration issue, ignoring it
return;
}
println!("result.stdout = {}", result.stdout);
println!("result.stderr = {}", result.stderr);
if !result.stderr.contains("Could not find uid") {
if !result.stderr_str().contains("Could not find uid") {
// Verify that the id found by --user/-u exists in the list
assert!(result.stdout.contains(&uid));
result.success().stdout_contains(&uid);
}
}
@ -47,88 +43,64 @@ fn test_id_from_name() {
return;
}
let scene = TestScenario::new(util_name!());
let result = scene.ucmd().arg(&username).succeeds();
println!("result.stdout = {}", result.stdout);
println!("result.stderr = {}", result.stderr);
assert!(result.success);
let uid = String::from(result.stdout.trim());
let result = scene.ucmd().succeeds();
println!("result.stdout = {}", result.stdout);
println!("result.stderr = {}", result.stderr);
// Verify that the id found by --user/-u exists in the list
assert!(result.stdout.contains(&uid));
// Verify that the username found by whoami exists in the list
assert!(result.stdout.contains(&username));
let result = new_ucmd!().arg(&username).succeeds();
let uid = result.stdout_str().trim();
new_ucmd!().succeeds()
// Verify that the id found by --user/-u exists in the list
.stdout_contains(uid)
// Verify that the username found by whoami exists in the list
.stdout_contains(username);
}
#[test]
fn test_id_name_from_id() {
let mut scene = TestScenario::new(util_name!());
let result = scene.ucmd().arg("-u").run();
println!("result.stdout = {}", result.stdout);
println!("result.stderr = {}", result.stderr);
assert!(result.success);
let uid = String::from(result.stdout.trim());
let result = new_ucmd!().arg("-u").succeeds();
let uid = result.stdout_str().trim();
scene = TestScenario::new(util_name!());
let result = scene.ucmd().arg("-nu").arg(uid).run();
let result = new_ucmd!().arg("-nu").arg(uid).run();
if is_ci() && result.stderr.contains("No such user/group") {
// In the CI, some server are failing to return whoami.
// As seems to be a configuration issue, ignoring it
return;
}
println!("result.stdout = {}", result.stdout);
println!("result.stderr = {}", result.stderr);
assert!(result.success);
let username_id = String::from(result.stdout.trim());
let username_id = result
.success()
.stdout_str()
.trim();
scene = TestScenario::new("whoami");
let result = scene.cmd("whoami").run();
let scene = TestScenario::new("whoami");
let result = scene.cmd("whoami").succeeds();
let username_whoami = result.stdout.trim();
let username_whoami = result.stdout_str().trim();
assert_eq!(username_id, username_whoami);
}
#[test]
fn test_id_group() {
let scene = TestScenario::new(util_name!());
let mut result = scene.ucmd().arg("-g").succeeds();
println!("result.stdout = {}", result.stdout);
println!("result.stderr = {}", result.stderr);
assert!(result.success);
let s1 = String::from(result.stdout.trim());
let mut result = new_ucmd!().arg("-g").succeeds();
let s1 = result.stdout_str().trim();
assert!(s1.parse::<f64>().is_ok());
result = scene.ucmd().arg("--group").succeeds();
println!("result.stdout = {}", result.stdout);
println!("result.stderr = {}", result.stderr);
assert!(result.success);
let s1 = String::from(result.stdout.trim());
result = new_ucmd!().arg("--group").succeeds();
let s1 = result.stdout_str().trim();
assert!(s1.parse::<f64>().is_ok());
}
#[test]
fn test_id_groups() {
let scene = TestScenario::new(util_name!());
let result = scene.ucmd().arg("-G").succeeds();
println!("result.stdout = {}", result.stdout);
println!("result.stderr = {}", result.stderr);
let result = new_ucmd!().arg("-G").succeeds();
assert!(result.success);
let groups = result.stdout.trim().split_whitespace();
let groups = result.stdout_str().trim().split_whitespace();
for s in groups {
assert!(s.parse::<f64>().is_ok());
}
let result = scene.ucmd().arg("--groups").succeeds();
println!("result.stdout = {}", result.stdout);
println!("result.stderr = {}", result.stderr);
let result = new_ucmd!().arg("--groups").succeeds();
assert!(result.success);
let groups = result.stdout.trim().split_whitespace();
let groups = result.stdout_str().trim().split_whitespace();
for s in groups {
assert!(s.parse::<f64>().is_ok());
}
@ -136,15 +108,12 @@ fn test_id_groups() {
#[test]
fn test_id_user() {
let scene = TestScenario::new(util_name!());
let mut result = scene.ucmd().arg("-u").succeeds();
assert!(result.success);
let s1 = String::from(result.stdout.trim());
let mut result = new_ucmd!().arg("-u").succeeds();
let s1 = result.stdout_str().trim();
assert!(s1.parse::<f64>().is_ok());
result = scene.ucmd().arg("--user").succeeds();
assert!(result.success);
let s1 = String::from(result.stdout.trim());
result = new_ucmd!().arg("--user").succeeds();
let s1 = result.stdout_str().trim();
assert!(s1.parse::<f64>().is_ok());
}
@ -156,17 +125,13 @@ fn test_id_pretty_print() {
return;
}
let scene = TestScenario::new(util_name!());
let result = scene.ucmd().arg("-p").run();
if result.stdout.trim() == "" {
let result = new_ucmd!().arg("-p").run();
if result.stdout_str().trim() == "" {
// Sometimes, the CI is failing here with
// old rust versions on Linux
return;
}
println!("result.stdout = {}", result.stdout);
println!("result.stderr = {}", result.stderr);
assert!(result.success);
assert!(result.stdout.contains(&username));
result.success().stdout_contains(username);
}
#[test]
@ -176,12 +141,7 @@ fn test_id_password_style() {
// Sometimes, the CI is failing here
return;
}
let scene = TestScenario::new(util_name!());
let result = scene.ucmd().arg("-P").succeeds();
println!("result.stdout = {}", result.stdout);
println!("result.stderr = {}", result.stderr);
assert!(result.success);
assert!(result.stdout.starts_with(&username));
let result = new_ucmd!().arg("-P").succeeds();
assert!(result.stdout_str().starts_with(&username));
}

View file

@ -195,12 +195,8 @@ fn test_install_mode_numeric() {
let mode_arg = "-m 0333";
at.mkdir(dir2);
let result = scene.ucmd().arg(mode_arg).arg(file).arg(dir2).run();
scene.ucmd().arg(mode_arg).arg(file).arg(dir2).succeeds();
println!("stderr = {:?}", result.stderr);
println!("stdout = {:?}", result.stdout);
assert!(result.success);
let dest_file = &format!("{}/{}", dir2, file);
assert!(at.file_exists(file));
assert!(at.file_exists(dest_file));
@ -313,16 +309,13 @@ fn test_install_target_new_file_with_group() {
.arg(format!("{}/{}", dir, file))
.run();
println!("stderr = {:?}", result.stderr);
println!("stdout = {:?}", result.stdout);
if is_ci() && result.stderr.contains("error: no such group:") {
if is_ci() && result.stderr_str().contains("error: no such group:") {
// In the CI, some server are failing to return the group.
// As seems to be a configuration issue, ignoring it
return;
}
assert!(result.success);
result.success();
assert!(at.file_exists(file));
assert!(at.file_exists(&format!("{}/{}", dir, file)));
}
@ -343,16 +336,13 @@ fn test_install_target_new_file_with_owner() {
.arg(format!("{}/{}", dir, file))
.run();
println!("stderr = {:?}", result.stderr);
println!("stdout = {:?}", result.stdout);
if is_ci() && result.stderr.contains("error: no such user:") {
// In the CI, some server are failing to return the user id.
// As seems to be a configuration issue, ignoring it
return;
}
assert!(result.success);
result.success();
assert!(at.file_exists(file));
assert!(at.file_exists(&format!("{}/{}", dir, file)));
}
@ -366,13 +356,10 @@ fn test_install_target_new_file_failing_nonexistent_parent() {
at.touch(file1);
let err = ucmd
.arg(file1)
ucmd.arg(file1)
.arg(format!("{}/{}", dir, file2))
.fails()
.stderr;
assert!(err.contains("not a directory"))
.stderr_contains(&"not a directory");
}
#[test]
@ -417,18 +404,12 @@ fn test_install_copy_file() {
#[test]
#[cfg(target_os = "linux")]
fn test_install_target_file_dev_null() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
let (at, mut ucmd) = at_and_ucmd!();
let file1 = "/dev/null";
let file2 = "target_file";
let result = scene.ucmd().arg(file1).arg(file2).run();
println!("stderr = {:?}", result.stderr);
println!("stdout = {:?}", result.stdout);
assert!(result.success);
ucmd.arg(file1).arg(file2).succeeds();
assert!(at.file_exists(file2));
}

View file

@ -520,10 +520,7 @@ fn test_symlink_no_deref_dir() {
scene.ucmd().args(&["-sn", dir1, link]).fails();
// Try with the no-deref
let result = scene.ucmd().args(&["-sfn", dir1, link]).run();
println!("stdout {}", result.stdout);
println!("stderr {}", result.stderr);
assert!(result.success);
scene.ucmd().args(&["-sfn", dir1, link]).succeeds();
assert!(at.dir_exists(dir1));
assert!(at.dir_exists(dir2));
assert!(at.is_symlink(link));
@ -566,10 +563,7 @@ fn test_symlink_no_deref_file() {
scene.ucmd().args(&["-sn", file1, link]).fails();
// Try with the no-deref
let result = scene.ucmd().args(&["-sfn", file1, link]).run();
println!("stdout {}", result.stdout);
println!("stderr {}", result.stderr);
assert!(result.success);
scene.ucmd().args(&["-sfn", file1, link]).succeeds();
assert!(at.file_exists(file1));
assert!(at.file_exists(file2));
assert!(at.is_symlink(link));

View file

@ -3,23 +3,19 @@ use std::env;
#[test]
fn test_normal() {
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd.run();
println!("result.stdout = {}", result.stdout);
println!("result.stderr = {}", result.stderr);
let result = new_ucmd!().run();
println!("env::var(CI).is_ok() = {}", env::var("CI").is_ok());
for (key, value) in env::vars() {
println!("{}: {}", key, value);
}
if (is_ci() || is_wsl()) && result.stderr.contains("error: no login name") {
if (is_ci() || is_wsl()) && result.stderr_str().contains("error: no login name") {
// ToDO: investigate WSL failure
// In the CI, some server are failing to return logname.
// As seems to be a configuration issue, ignoring it
return;
}
assert!(result.success);
assert!(!result.stdout.trim().is_empty());
result.success();
assert!(!result.stdout_str().trim().is_empty());
}

View file

@ -8,6 +8,25 @@ fn test_helper(file_name: &str, args: &str) {
.stdout_is_fixture(format!("{}.expected", file_name));
}
#[test]
fn test_months_whitespace() {
test_helper("months-whitespace", "-M");
}
#[test]
fn test_version_empty_lines() {
new_ucmd!()
.arg("-V")
.arg("version-empty-lines.txt")
.succeeds()
.stdout_is("\n\n\n\n\n\n\n1.2.3-alpha\n1.2.3-alpha2\n\t\t\t1.12.4\n11.2.3\n");
}
#[test]
fn test_human_numeric_whitespace() {
test_helper("human-numeric-whitespace", "-h");
}
#[test]
fn test_multiple_decimals_general() {
new_ucmd!()

View file

@ -25,19 +25,15 @@ fn test_stdbuf_line_buffered_stdout() {
#[cfg(not(target_os = "windows"))]
#[test]
fn test_stdbuf_no_buffer_option_fails() {
new_ucmd!()
.args(&["head"])
.pipe_in("The quick brown fox jumps over the lazy dog.")
.fails()
.stderr_is(
"error: The following required arguments were not provided:\n \
new_ucmd!().args(&["head"]).fails().stderr_is(
"error: The following required arguments were not provided:\n \
--error <MODE>\n \
--input <MODE>\n \
--output <MODE>\n\n\
USAGE:\n \
stdbuf OPTION... COMMAND\n\n\
For more information try --help",
);
);
}
#[cfg(not(target_os = "windows"))]
@ -55,7 +51,6 @@ fn test_stdbuf_trailing_var_arg() {
fn test_stdbuf_line_buffering_stdin_fails() {
new_ucmd!()
.args(&["-i", "L", "head"])
.pipe_in("The quick brown fox jumps over the lazy dog.")
.fails()
.stderr_is("stdbuf: error: line buffering stdin is meaningless\nTry 'stdbuf --help' for more information.");
}
@ -65,7 +60,6 @@ fn test_stdbuf_line_buffering_stdin_fails() {
fn test_stdbuf_invalid_mode_fails() {
new_ucmd!()
.args(&["-i", "1024R", "head"])
.pipe_in("The quick brown fox jumps over the lazy dog.")
.fails()
.stderr_is("stdbuf: error: invalid mode 1024R\nTry 'stdbuf --help' for more information.");
}

View file

@ -29,6 +29,7 @@ fn set_file_times(at: &AtPath, path: &str, atime: FileTime, mtime: FileTime) {
fn str_to_filetime(format: &str, s: &str) -> FileTime {
let mut tm = time::strptime(s, format).unwrap();
tm.tm_utcoff = time::now().tm_utcoff;
tm.tm_isdst = -1; // Unknown flag DST
let ts = tm.to_timespec();
FileTime::from_unix_time(ts.sec as i64, ts.nsec as u32)
}
@ -352,3 +353,21 @@ fn test_touch_set_date() {
assert_eq!(atime, start_of_year);
assert_eq!(mtime, start_of_year);
}
#[test]
fn test_touch_mtime_dst_succeeds() {
let (at, mut ucmd) = at_and_ucmd!();
let file = "test_touch_set_mtime_dst_succeeds";
ucmd.args(&["-m", "-t", "202103140300", file])
.succeeds()
.no_stderr();
assert!(at.file_exists(file));
let target_time = str_to_filetime("%Y%m%d%H%M", "202103140300");
let (_, mtime) = get_file_times(&at, file);
eprintln!("target_time: {:?}", target_time);
eprintln!("mtime: {:?}", mtime);
assert!(target_time == mtime);
}

View file

@ -33,6 +33,8 @@ static ALREADY_RUN: &str = " you have already run this UCommand, if you want to
testing();";
static MULTIPLE_STDIN_MEANINGLESS: &str = "Ucommand is designed around a typical use case of: provide args and input stream -> spawn process -> block until completion -> return output streams. For verifying that a particular section of the input stream is what causes a particular behavior, use the Command type directly.";
static NO_STDIN_MEANINGLESS: &str = "Setting this flag has no effect if there is no stdin";
/// Test if the program is running under CI
pub fn is_ci() -> bool {
std::env::var("CI")
@ -688,6 +690,7 @@ pub struct UCommand {
tmpd: Option<Rc<TempDir>>,
has_run: bool,
stdin: Option<Vec<u8>>,
ignore_stdin_write_error: bool,
}
impl UCommand {
@ -717,6 +720,7 @@ impl UCommand {
},
comm_string: String::from(arg.as_ref().to_str().unwrap()),
stdin: None,
ignore_stdin_write_error: false,
}
}
@ -769,6 +773,17 @@ impl UCommand {
self.pipe_in(contents)
}
/// Ignores error caused by feeding stdin to the command.
/// 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.stdin.is_none() {
panic!("{}", NO_STDIN_MEANINGLESS);
}
self.ignore_stdin_write_error = true;
self
}
pub fn env<K, V>(&mut self, key: K, val: V) -> &mut UCommand
where
K: AsRef<OsStr>,
@ -789,7 +804,7 @@ impl UCommand {
}
self.has_run = true;
log_info("run", &self.comm_string);
let mut result = self
let mut child = self
.raw
.stdin(Stdio::piped())
.stdout(Stdio::piped())
@ -798,15 +813,19 @@ impl UCommand {
.unwrap();
if let Some(ref input) = self.stdin {
result
let write_result = child
.stdin
.take()
.unwrap_or_else(|| panic!("Could not take child process stdin"))
.write_all(input)
.unwrap_or_else(|e| panic!("{}", e));
.write_all(input);
if !self.ignore_stdin_write_error {
if let Err(e) = write_result {
panic!("failed to write to stdin of child: {}", e)
}
}
}
result
child
}
/// Spawns the command, feeds the stdin if any, waits for the result

View file

@ -0,0 +1,11 @@
456K
4568K
456M
6.2G

View file

@ -0,0 +1,11 @@
456K
456M
4568K
6.2G

View file

@ -0,0 +1,8 @@
JAN
FEb
apr
apr
JUNNNN
AUG

View file

@ -0,0 +1,8 @@
JAN
JUNNNN
AUG
apr
apr
FEb

View file

@ -0,0 +1,11 @@
1.2.3-alpha
1.2.3-alpha2
11.2.3
1.12.4

View file

@ -0,0 +1,11 @@
11.2.3
1.2.3-alpha2
1.2.3-alpha
1.12.4