Skip to content

Commit e502d89

Browse files
committed
test: existing file is newer than non-existing
existing -nt non-existing => true non-existing -nt existing => false existing -ot non-existing => false non-existing -ot existing => true
1 parent ceeacf4 commit e502d89

File tree

4 files changed

+116
-27
lines changed

4 files changed

+116
-27
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/uu/test/Cargo.toml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,13 @@ path = "src/test.rs"
1919

2020
[dependencies]
2121
clap = { workspace = true }
22+
fluent = { workspace = true }
2223
libc = { workspace = true }
23-
uucore = { workspace = true, features = ["process"] }
2424
thiserror = { workspace = true }
25-
fluent = { workspace = true }
25+
uucore = { workspace = true, features = ["process"] }
26+
27+
[dev-dependencies]
28+
tempfile = { workspace = true }
2629

2730
[[bin]]
2831
name = "test"

src/uu/test/src/test.rs

Lines changed: 90 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -205,24 +205,26 @@ fn integers(a: &OsStr, b: &OsStr, op: &OsStr) -> ParseResult<bool> {
205205

206206
/// Operations to compare files metadata
207207
/// `a` is the left hand side
208-
/// `b` is the left hand side
208+
/// `b` is the right hand side
209209
/// `op` the operation (ex: -ef, -nt, etc)
210210
fn files(a: &OsStr, b: &OsStr, op: &OsStr) -> ParseResult<bool> {
211-
// Don't manage the error. GNU doesn't show error when doing
212-
// test foo -nt bar
213-
let (Ok(f_a), Ok(f_b)) = (fs::metadata(a), fs::metadata(b)) else {
214-
return Ok(false);
215-
};
211+
let f_a = fs::metadata(a);
212+
let f_b = fs::metadata(b);
216213

217-
Ok(match op.to_str() {
214+
let result = match (op.to_str(), f_a, f_b) {
218215
#[cfg(unix)]
219-
Some("-ef") => f_a.ino() == f_b.ino() && f_a.dev() == f_b.dev(),
216+
(Some("-ef"), Ok(f_a), Ok(f_b)) => f_a.ino() == f_b.ino() && f_a.dev() == f_b.dev(),
220217
#[cfg(not(unix))]
221-
Some("-ef") => unimplemented!(),
222-
Some("-nt") => f_a.modified().unwrap() > f_b.modified().unwrap(),
223-
Some("-ot") => f_a.modified().unwrap() < f_b.modified().unwrap(),
224-
_ => return Err(ParseError::UnknownOperator(op.quote().to_string())),
225-
})
218+
(Some("-ef"), Ok(_), Ok(_)) => unimplemented!(),
219+
(Some("-nt"), Ok(f_a), Ok(f_b)) => f_a.modified().unwrap() > f_b.modified().unwrap(),
220+
(Some("-nt"), Ok(_), _) => true,
221+
(Some("-ot"), Ok(f_a), Ok(f_b)) => f_a.modified().unwrap() < f_b.modified().unwrap(),
222+
(Some("-ot"), _, Ok(_)) => true,
223+
(Some("-ef" | "-nt" | "-ot"), _, _) => false,
224+
(_, _, _) => return Err(ParseError::UnknownOperator(op.quote().to_string())),
225+
};
226+
227+
Ok(result)
226228
}
227229

228230
fn isatty(fd: &OsStr) -> ParseResult<bool> {
@@ -347,8 +349,81 @@ fn path(path: &OsStr, condition: &PathCondition) -> bool {
347349

348350
#[cfg(test)]
349351
mod tests {
350-
use super::integers;
351-
use std::ffi::OsStr;
352+
use super::*;
353+
use std::{ffi::OsStr, time::UNIX_EPOCH};
354+
use tempfile::NamedTempFile;
355+
356+
#[test]
357+
fn test_files_with_unknown_op() {
358+
let a = NamedTempFile::new().unwrap();
359+
let b = NamedTempFile::new().unwrap();
360+
let a = OsStr::new(a.path());
361+
let b = OsStr::new(b.path());
362+
let op = OsStr::new("unknown_op");
363+
364+
assert!(files(a, b, op).is_err());
365+
}
366+
367+
#[test]
368+
#[cfg(unix)]
369+
fn test_files_with_ef_op() {
370+
let a = NamedTempFile::new().unwrap();
371+
let b = NamedTempFile::new().unwrap();
372+
let a = OsStr::new(a.path());
373+
let b = OsStr::new(b.path());
374+
let op = OsStr::new("-ef");
375+
376+
assert!(files(a, a, op).unwrap());
377+
assert!(!files(a, b, op).unwrap());
378+
assert!(!files(b, a, op).unwrap());
379+
380+
let existing_file = a;
381+
let non_existing_file = OsStr::new("non_existing_file");
382+
383+
assert!(!files(existing_file, non_existing_file, op).unwrap());
384+
assert!(!files(non_existing_file, existing_file, op).unwrap());
385+
assert!(!files(non_existing_file, non_existing_file, op).unwrap());
386+
}
387+
388+
#[test]
389+
fn test_files_with_nt_op() {
390+
let older_file = NamedTempFile::new().unwrap();
391+
older_file.as_file().set_modified(UNIX_EPOCH).unwrap();
392+
let older_file = OsStr::new(older_file.path());
393+
let newer_file = NamedTempFile::new().unwrap();
394+
let newer_file = OsStr::new(newer_file.path());
395+
let op = OsStr::new("-nt");
396+
397+
assert!(files(newer_file, older_file, op).unwrap());
398+
assert!(!files(older_file, newer_file, op).unwrap());
399+
400+
let existing_file = newer_file;
401+
let non_existing_file = OsStr::new("non_existing_file");
402+
403+
assert!(files(existing_file, non_existing_file, op).unwrap());
404+
assert!(!files(non_existing_file, existing_file, op).unwrap());
405+
assert!(!files(non_existing_file, non_existing_file, op).unwrap());
406+
}
407+
408+
#[test]
409+
fn test_files_with_ot_op() {
410+
let older_file = NamedTempFile::new().unwrap();
411+
older_file.as_file().set_modified(UNIX_EPOCH).unwrap();
412+
let older_file = OsStr::new(older_file.path());
413+
let newer_file = NamedTempFile::new().unwrap();
414+
let newer_file = OsStr::new(newer_file.path());
415+
let op = OsStr::new("-ot");
416+
417+
assert!(!files(newer_file, older_file, op).unwrap());
418+
assert!(files(older_file, newer_file, op).unwrap());
419+
420+
let existing_file = newer_file;
421+
let non_existing_file = OsStr::new("non_existing_file");
422+
423+
assert!(!files(existing_file, non_existing_file, op).unwrap());
424+
assert!(files(non_existing_file, existing_file, op).unwrap());
425+
assert!(!files(non_existing_file, non_existing_file, op).unwrap());
426+
}
352427

353428
#[test]
354429
fn test_integer_op() {

tests/by-util/test_test.rs

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,8 @@
55

66
// spell-checker:ignore (words) egid euid pseudofloat
77

8-
use uutests::at_and_ucmd;
9-
use uutests::new_ucmd;
108
use uutests::util::TestScenario;
11-
use uutests::util_name;
9+
use uutests::{at_and_ucmd, new_ucmd, util_name};
1210

1311
#[test]
1412
fn test_empty_test_equivalent_to_false() {
@@ -337,14 +335,26 @@ fn test_file_is_newer_than_and_older_than_itself() {
337335
}
338336

339337
#[test]
340-
fn test_non_existing_files() {
341-
let scenario = TestScenario::new(util_name!());
338+
fn test_file_is_newer_than_non_existing_file() {
339+
new_ucmd!()
340+
.args(&["non_existing_file", "-nt", "regular_file"])
341+
.fails_with_code(1)
342+
.no_output();
342343

343-
let result = scenario
344-
.ucmd()
345-
.args(&["newer_file", "-nt", "regular_file"])
346-
.fails_with_code(1);
347-
assert!(result.stderr().is_empty());
344+
new_ucmd!()
345+
.args(&["regular_file", "-nt", "non_existing_file"])
346+
.succeeds()
347+
.no_output();
348+
349+
new_ucmd!()
350+
.args(&["non_existing_file", "-ot", "regular_file"])
351+
.succeeds()
352+
.no_output();
353+
354+
new_ucmd!()
355+
.args(&["regular_file", "-ot", "non_existing_file"])
356+
.fails_with_code(1)
357+
.no_output();
348358
}
349359

350360
#[test]

0 commit comments

Comments
 (0)