diff --git a/src/uu/du/Cargo.toml b/src/uu/du/Cargo.toml index bb9a2a97b..bc53986b3 100644 --- a/src/uu/du/Cargo.toml +++ b/src/uu/du/Cargo.toml @@ -19,7 +19,7 @@ chrono = { workspace = true } # For the --exclude & --exclude-from options glob = { workspace = true } clap = { workspace = true } -uucore = { workspace = true } +uucore = { workspace = true, features = ["format"] } [target.'cfg(target_os = "windows")'.dependencies] windows-sys = { workspace = true, features = [ diff --git a/src/uu/du/src/du.rs b/src/uu/du/src/du.rs index 1935248da..74fa4154d 100644 --- a/src/uu/du/src/du.rs +++ b/src/uu/du/src/du.rs @@ -75,9 +75,6 @@ const ABOUT: &str = help_about!("du.md"); const AFTER_HELP: &str = help_section!("after help", "du.md"); const USAGE: &str = help_usage!("du.md"); -// TODO: Support Z & Y (currently limited by size of u64) -const UNITS: [(char, u32); 6] = [('E', 6), ('P', 5), ('T', 4), ('G', 3), ('M', 2), ('K', 1)]; - struct TraversalOptions { all: bool, separate_dirs: bool, @@ -117,7 +114,8 @@ enum Time { #[derive(Clone)] enum SizeFormat { - Human(u64), + HumanDecimal, + HumanBinary, BlockSize(u64), } @@ -549,18 +547,14 @@ impl StatPrinter { return size.to_string(); } match self.size_format { - SizeFormat::Human(multiplier) => { - if size == 0 { - return "0".to_string(); - } - for &(unit, power) in &UNITS { - let limit = multiplier.pow(power); - if size >= limit { - return format!("{:.1}{}", (size as f64) / (limit as f64), unit); - } - } - format!("{size}B") - } + SizeFormat::HumanDecimal => uucore::format::human::human_readable( + size, + uucore::format::human::SizeFormat::Decimal, + ), + SizeFormat::HumanBinary => uucore::format::human::human_readable( + size, + uucore::format::human::SizeFormat::Binary, + ), SizeFormat::BlockSize(block_size) => div_ceil(size, block_size).to_string(), } } @@ -688,9 +682,9 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { }); let size_format = if matches.get_flag(options::HUMAN_READABLE) { - SizeFormat::Human(1024) + SizeFormat::HumanBinary } else if matches.get_flag(options::SI) { - SizeFormat::Human(1000) + SizeFormat::HumanDecimal } else if matches.get_flag(options::BYTES) { SizeFormat::BlockSize(1) } else if matches.get_flag(options::BLOCK_SIZE_1K) { diff --git a/tests/by-util/test_du.rs b/tests/by-util/test_du.rs index 2bc694acb..a71cd4623 100644 --- a/tests/by-util/test_du.rs +++ b/tests/by-util/test_du.rs @@ -543,6 +543,34 @@ fn test_du_h_flag_empty_file() { .stdout_only("0\tempty.txt\n"); } +#[test] +fn test_du_h_precision() { + let test_cases = [ + (133456345, "128M"), + (12 * 1024 * 1024, "12M"), + (8500, "8.4K"), + ]; + + for &(test_len, expected_output) in &test_cases { + let (at, mut ucmd) = at_and_ucmd!(); + + let fpath = at.plus("test.txt"); + std::fs::File::create(&fpath) + .expect("cannot create test file") + .set_len(test_len) + .expect("cannot truncate test len to size"); + ucmd.arg("-h") + .arg("--apparent-size") + .arg(&fpath) + .succeeds() + .stdout_only(format!( + "{}\t{}\n", + expected_output, + &fpath.to_string_lossy() + )); + } +} + #[cfg(feature = "touch")] #[test] fn test_du_time() {