diff --git a/src/uu/du/src/du.rs b/src/uu/du/src/du.rs index d8bfd4446a1..a0922ce03fc 100644 --- a/src/uu/du/src/du.rs +++ b/src/uu/du/src/du.rs @@ -959,6 +959,40 @@ fn read_files_from(file_name: &OsStr) -> Result, std::io::Error> { Ok(paths) } +fn get_block_size_arg_index_if_present(matches: &ArgMatches, flag: &str) -> Option { + if matches.get_flag(flag) { + // Indices of returns index even if flag is not present, thats why we need to if guard it + matches + .indices_of(flag) + .and_then(|mut indices| indices.next_back()) + } else { + None + } +} + +fn handle_block_size_arg_override(matches: &ArgMatches) -> Option { + let candidates = [ + ( + SizeFormat::BlockSize(1), + get_block_size_arg_index_if_present(matches, options::BYTES), + ), + ( + SizeFormat::BlockSize(1024), + get_block_size_arg_index_if_present(matches, options::BLOCK_SIZE_1K), + ), + ( + SizeFormat::BlockSize(1024 * 1024), + get_block_size_arg_index_if_present(matches, options::BLOCK_SIZE_1M), + ), + ]; + + candidates + .into_iter() + .filter(|(_, idx)| idx.is_some()) + .max_by_key(|&(_, idx)| idx.unwrap_or(0)) + .map(|(size_format, _)| size_format) +} + #[uucore::main] #[allow(clippy::cognitive_complexity)] pub fn uumain(args: impl uucore::Args) -> UResult<()> { @@ -1014,12 +1048,8 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { SizeFormat::HumanBinary } else if matches.get_flag(options::SI) { SizeFormat::HumanDecimal - } else if matches.get_flag(options::BYTES) { - SizeFormat::BlockSize(1) - } else if matches.get_flag(options::BLOCK_SIZE_1K) { - SizeFormat::BlockSize(1024) - } else if matches.get_flag(options::BLOCK_SIZE_1M) { - SizeFormat::BlockSize(1024 * 1024) + } else if let Some(size_format) = handle_block_size_arg_override(&matches) { + size_format } else { let block_size_str = matches.get_one::(options::BLOCK_SIZE); let block_size = read_block_size(block_size_str.map(AsRef::as_ref))?; diff --git a/tests/by-util/test_du.rs b/tests/by-util/test_du.rs index c89cd46678c..2be6ef02c36 100644 --- a/tests/by-util/test_du.rs +++ b/tests/by-util/test_du.rs @@ -2058,3 +2058,96 @@ fn test_du_symlinks_multiple_links_in_args() { result.stdout_contains("dir1/file"); result.stdout_does_not_contain("dir1/link"); } + +#[test] +fn test_block_size_args_override() { + let ts = TestScenario::new(util_name!()); + let at = &ts.fixtures; + let dir = "override_args_dir"; + + at.mkdir(dir); + let fpath = at.plus(format!("{dir}/file")); + std::fs::File::create(fpath) + .expect("cannot create test file") + .set_len(100_000_000) + .expect("cannot set file size"); + + let fpath2 = at.plus(format!("{dir}/file_2")); + std::fs::File::create(fpath2) + .expect("cannot create test file") + .set_len(100_000_000) + .expect("cannot set file size"); + + let test_cases = [ + (["-sk", "-m"], "-sm"), + (["-sk", "-b"], "-sb"), + (["-sm", "-k"], "-sk"), + ]; + + for (idx, (overwriting_args, expected)) in test_cases.into_iter().enumerate() { + let overridden_args = ts + .ucmd() + .arg(dir) + .args(&overwriting_args) + .succeeds() + .stdout_move_str(); + + let single_args = ts + .ucmd() + .arg(dir) + .arg(expected) + .succeeds() + .stdout_move_str(); + + assert_eq!( + overridden_args, single_args, + "The last argument of m, k and b should overwrite. Run: {idx}" + ); + } +} + +#[test] +fn test_block_override_b_still_has_apparent_size() { + let ts = TestScenario::new(util_name!()); + let at = &ts.fixtures; + let dir = "override_args_dir"; + + at.mkdir(dir); + let fpath = at.plus(format!("{dir}/file")); + std::fs::File::create(fpath) + .expect("cannot create test file") + .set_len(100_000_000) + .expect("cannot set file size"); + + let fpath2 = at.plus(format!("{dir}/file_2")); + std::fs::File::create(fpath2) + .expect("cannot create test file") + .set_len(100_000_000) + .expect("cannot set file size"); + + let test_cases = [ + (["-sb", "-m"], ["-sm", "--apparent-size"]), + (["-sb", "-k"], ["-sk", "--apparent-size"]), + ]; + + for (idx, (overwriting_args, expected)) in test_cases.into_iter().enumerate() { + let overridden_args = ts + .ucmd() + .arg(dir) + .args(&overwriting_args) + .succeeds() + .stdout_move_str(); + + let single_args = ts + .ucmd() + .arg(dir) + .args(&expected) + .succeeds() + .stdout_move_str(); + + assert_eq!( + overridden_args, single_args, + "Overwriting the b flag should still leave --apparent-size active. Run: {idx}" + ); + } +}