Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/uu/du/src/du.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1080,6 +1080,9 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let (print_tx, rx) = mpsc::channel::<UResult<StatPrintInfo>>();
let printing_thread = thread::spawn(move || stat_printer.print_stats(&rx));

// Check existence of path provided in argument and duplicates
let mut seen_inodes: HashSet<FileInfo> = HashSet::new();

'loop_file: for path in files {
// Skip if we don't want to ignore anything
if !&traversal_options.excludes.is_empty() {
Expand All @@ -1098,9 +1101,6 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
}
}

// Check existence of path provided in argument
let mut seen_inodes: HashSet<FileInfo> = HashSet::new();

// Determine which traversal method to use
#[cfg(all(unix, not(target_os = "redox")))]
let use_safe_traversal = traversal_options.dereference != Deref::All;
Expand Down
33 changes: 32 additions & 1 deletion tests/by-util/test_du.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

// spell-checker:ignore (paths) atim sublink subwords azerty azeaze xcwww azeaz amaz azea qzerty tazerty tsublink testfile1 testfile2 filelist fpath testdir testfile
// spell-checker:ignore selfref ELOOP smallfile

Expand Down Expand Up @@ -1763,6 +1762,38 @@ fn test_du_inodes_total_text() {
assert!(parts[0].parse::<u64>().is_ok());
}

#[test]
fn test_du_summary_total_mega_duplicates() {
let ts = TestScenario::new_fresh(util_name!());
let at = &ts.fixtures;
const BYTES_PER_MIB: usize = 1024 * 1024;

at.fill_bytes("file1", 3 * BYTES_PER_MIB, true);

at.mkdir("dir1");
at.mkdir("dir2");

at.fill_bytes("dir1/file1", 5 * BYTES_PER_MIB, true);
at.fill_bytes("dir2/file1", 7 * BYTES_PER_MIB, true);

let result = ts
.ucmd()
.args(&["--apparent-size", "-smc", "dir1", "."])
.succeeds();

#[cfg(any(target_os = "linux", target_os = "android"))]
{
let result_ref_res = expected_result(&ts, &["--apparent-size", "-smc", "dir1", "."]);
if let Ok(result_ref) = result_ref_res {
println!("{}", result_ref.stdout_str());
assert_eq!(result.stdout_str(), result_ref.stdout_str());
return;
}
}

assert_eq!(result.stdout_str(), "5\tdir1\n10\t.\n15\ttotal\n");
}

#[test]
fn test_du_threshold_no_suggested_values() {
// tested by tests/du/threshold
Expand Down
82 changes: 72 additions & 10 deletions tests/uutests/src/lib/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use nix::pty::OpenptyResult;
#[cfg(unix)]
use nix::sys;
use pretty_assertions::assert_eq;
use rand::Rng;
#[cfg(unix)]
use rlimit::setrlimit;
use std::borrow::Cow;
Expand Down Expand Up @@ -1039,6 +1040,17 @@ impl AtPath {
.unwrap_or_else(|e| panic!("Couldn't write {name}: {e}"));
}

pub fn fill_bytes(&self, name: &str, size_bytes: usize, use_rng: bool) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i don't think we need to extend uutests for this.
could you please find another way? thanks

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it okay if I move those utility functions to du tests file?

let mut f = OpenOptions::new()
.create(true)
.write(true)
.truncate(true)
.append(false)
.open(self.plus(name))
.unwrap();
fill_file_rand(&mut f, size_bytes, use_rng).unwrap();
}

pub fn append(&self, name: impl AsRef<Path>, contents: &str) {
let name = name.as_ref();
log_info("write(append)", self.plus_as_string(name));
Expand Down Expand Up @@ -1342,32 +1354,44 @@ pub struct TestScenario {
}

impl TestScenario {
/// Using a standard fixture
pub fn new<T>(util_name: T) -> Self
where
T: AsRef<str>,
{
let tmpd = Rc::new(TempDir::new().unwrap());
println!("bin: {:?}", get_tests_binary!());
let ts = Self {
bin_path: PathBuf::from(get_tests_binary!()),
util_name: util_name.as_ref().into(),
fixtures: AtPath::new(tmpd.as_ref().path()),
tmpd,
#[cfg(any(target_os = "linux", target_os = "android", target_os = "freebsd"))]
tmp_fs_mountpoint: None,
};
let ts = Self::new_fresh(&util_name);

let mut fixture_path_builder = env::current_dir().unwrap();
fixture_path_builder.push(TESTS_DIR);
fixture_path_builder.push(FIXTURES_DIR);
fixture_path_builder.push(util_name.as_ref());

if let Ok(m) = fs::metadata(&fixture_path_builder) {
if m.is_dir() {
recursive_copy(&fixture_path_builder, &ts.fixtures.subdir).unwrap();
}
}

ts
}

/// Using an empty fixture
pub fn new_fresh<T>(util_name: T) -> Self
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it okay if I move those utility functions locally to du tests file?
@sylvestre

where
T: AsRef<str>,
{
let tmpd = Rc::new(TempDir::new().unwrap());
println!("bin: {:?}", get_tests_binary!());
Self {
bin_path: PathBuf::from(get_tests_binary!()),
util_name: util_name.as_ref().into(),
fixtures: AtPath::new(tmpd.as_ref().path()),
tmpd,
#[cfg(any(target_os = "linux", target_os = "android", target_os = "freebsd"))]
tmp_fs_mountpoint: None,
}
}

/// Returns builder for invoking the target uutils binary. Paths given are
/// treated relative to the environment's unique temporary test directory.
pub fn ucmd(&self) -> UCommand {
Expand Down Expand Up @@ -2865,6 +2889,44 @@ pub fn vec_of_size(n: usize) -> Vec<u8> {
result
}

pub fn fill_file_rand(
file: &mut std::fs::File,
size_bytes: usize,
use_rng: bool,
) -> io::Result<()> {
const CHUNK_SIZE: usize = 64 * 1024; // 64 kiB
let mut writer = BufWriter::new(file);
let mut written: usize = 0;
let mut to_write_len: usize;
let mut tx_buf = [b'a'; CHUNK_SIZE];
let mut tx_slice: &mut [u8];

if use_rng {
let mut rng = rand::rng();

while written < size_bytes {
to_write_len = (size_bytes - written).min(CHUNK_SIZE);
tx_slice = &mut tx_buf[..to_write_len];

rng.fill(tx_slice);

writer.write_all(tx_slice)?;
written += to_write_len;
}
} else {
while written < size_bytes {
to_write_len = (size_bytes - written).min(CHUNK_SIZE);
tx_slice = &mut tx_buf[..to_write_len];

writer.write_all(tx_slice)?;
written += to_write_len;
}
}

writer.flush()?;
Ok(())
}

pub fn whoami() -> String {
// Apparently some CI environments have configuration issues, e.g. with 'whoami' and 'id'.
//
Expand Down
Loading