From 19cc63df9ae94791856ab6e6853ced040d711fdc Mon Sep 17 00:00:00 2001 From: Ivan Majeru Date: Tue, 1 Feb 2022 20:32:56 +0200 Subject: [PATCH] dd: allow multiple instances of arguments Correct the behavior of `dd` when multiple arguments are provided. Before this commit, if the multiple arguments was provided then the validation error are returned. For example ``` $ printf '' | ./target/debug/dd status=none status=noxfer error: The argument '--status=' was provided more than once, but cannot be used multiple times USAGE: dd [OPTIONS] For more information try --help ``` The unittest was added for this case. --- src/uu/dd/src/dd.rs | 13 +++ src/uu/dd/src/parseargs/unit_tests.rs | 112 ++++++++++++++++++++++++++ 2 files changed, 125 insertions(+) diff --git a/src/uu/dd/src/dd.rs b/src/uu/dd/src/dd.rs index 54e3190ce..296c6c6b1 100644 --- a/src/uu/dd/src/dd.rs +++ b/src/uu/dd/src/dd.rs @@ -954,6 +954,7 @@ pub fn uu_app<'a>() -> App<'a> { .arg( Arg::new(options::INFILE) .long(options::INFILE) + .overrides_with(options::INFILE) .takes_value(true) .require_equals(true) .value_name("FILE") @@ -962,6 +963,7 @@ pub fn uu_app<'a>() -> App<'a> { .arg( Arg::new(options::OUTFILE) .long(options::OUTFILE) + .overrides_with(options::OUTFILE) .takes_value(true) .require_equals(true) .value_name("FILE") @@ -970,6 +972,7 @@ pub fn uu_app<'a>() -> App<'a> { .arg( Arg::new(options::IBS) .long(options::IBS) + .overrides_with(options::IBS) .takes_value(true) .require_equals(true) .value_name("N") @@ -978,6 +981,7 @@ pub fn uu_app<'a>() -> App<'a> { .arg( Arg::new(options::OBS) .long(options::OBS) + .overrides_with(options::OBS) .takes_value(true) .require_equals(true) .value_name("N") @@ -986,6 +990,7 @@ pub fn uu_app<'a>() -> App<'a> { .arg( Arg::new(options::BS) .long(options::BS) + .overrides_with(options::BS) .takes_value(true) .require_equals(true) .value_name("N") @@ -994,6 +999,7 @@ pub fn uu_app<'a>() -> App<'a> { .arg( Arg::new(options::CBS) .long(options::CBS) + .overrides_with(options::CBS) .takes_value(true) .require_equals(true) .value_name("N") @@ -1002,6 +1008,7 @@ pub fn uu_app<'a>() -> App<'a> { .arg( Arg::new(options::SKIP) .long(options::SKIP) + .overrides_with(options::SKIP) .takes_value(true) .require_equals(true) .value_name("N") @@ -1010,6 +1017,7 @@ pub fn uu_app<'a>() -> App<'a> { .arg( Arg::new(options::SEEK) .long(options::SEEK) + .overrides_with(options::SEEK) .takes_value(true) .require_equals(true) .value_name("N") @@ -1018,6 +1026,7 @@ pub fn uu_app<'a>() -> App<'a> { .arg( Arg::new(options::COUNT) .long(options::COUNT) + .overrides_with(options::COUNT) .takes_value(true) .require_equals(true) .value_name("N") @@ -1026,6 +1035,7 @@ pub fn uu_app<'a>() -> App<'a> { .arg( Arg::new(options::STATUS) .long(options::STATUS) + .overrides_with(options::STATUS) .takes_value(true) .require_equals(true) .value_name("LEVEL") @@ -1050,6 +1060,7 @@ Printing performance stats is also triggered by the INFO signal (where supported .arg( Arg::new(options::CONV) .long(options::CONV) + .overrides_with(options::CONV) .takes_value(true) .require_equals(true) .value_name("CONV") @@ -1087,6 +1098,7 @@ Conversion Flags: .arg( Arg::new(options::IFLAG) .long(options::IFLAG) + .overrides_with(options::IFLAG) .takes_value(true) .require_equals(true) .value_name("FLAG") @@ -1113,6 +1125,7 @@ General-Flags .arg( Arg::new(options::OFLAG) .long(options::OFLAG) + .overrides_with(options::OFLAG) .takes_value(true) .require_equals(true) .value_name("FLAG") diff --git a/src/uu/dd/src/parseargs/unit_tests.rs b/src/uu/dd/src/parseargs/unit_tests.rs index a72944309..64da4640f 100644 --- a/src/uu/dd/src/parseargs/unit_tests.rs +++ b/src/uu/dd/src/parseargs/unit_tests.rs @@ -299,6 +299,118 @@ fn test_status_level_noxfer() { assert_eq!(st, StatusLevel::Noxfer); } +#[test] +fn test_override_multiple_levels() { + let args = vec![ + String::from("dd"), + String::from("--if=foo.file"), + String::from("--if=correct.file"), + String::from("--of=bar.file"), + String::from("--of=correct.file"), + String::from("--ibs=256"), + String::from("--ibs=1024"), + String::from("--obs=256"), + String::from("--obs=1024"), + String::from("--cbs=1"), + String::from("--cbs=2"), + String::from("--skip=0"), + String::from("--skip=2"), + String::from("--seek=0"), + String::from("--seek=2"), + String::from("--status=none"), + String::from("--status=noxfer"), + String::from("--count=512"), + String::from("--count=1024"), + String::from("--conv=ascii,ucase"), + String::from("--conv=ebcdic,lcase,unblock"), + String::from("--iflag=direct,nocache"), + String::from("--iflag=count_bytes,skip_bytes"), + String::from("--oflag=append,direct"), + String::from("--oflag=append,seek_bytes"), + ]; + + let matches = uu_app().try_get_matches_from(args).unwrap(); + + // if + assert_eq!("correct.file", matches.value_of(options::INFILE).unwrap()); + + // of + assert_eq!("correct.file", matches.value_of(options::OUTFILE).unwrap()); + + // ibs + assert_eq!(1024, parse_ibs(&matches).unwrap()); + + // obs + assert_eq!(1024, parse_obs(&matches).unwrap()); + + // cbs + assert_eq!(2, parse_cbs(&matches).unwrap().unwrap()); + + // status + assert_eq!( + StatusLevel::Noxfer, + parse_status_level(&matches).unwrap().unwrap() + ); + + // skip + assert_eq!( + 200, + parse_skip_amt(&100, &IFlags::default(), &matches) + .unwrap() + .unwrap() + ); + + // seek + assert_eq!( + 200, + parse_seek_amt(&100, &OFlags::default(), &matches) + .unwrap() + .unwrap() + ); + + // conv + let exp = vec![ConvFlag::FmtEtoA, ConvFlag::LCase, ConvFlag::Unblock]; + let act = parse_flag_list::("conv", &matches).unwrap(); + assert_eq!(exp.len(), act.len()); + for cf in &exp { + assert!(exp.contains(cf)); + } + + // count + assert_eq!( + CountType::Bytes(1024), + parse_count( + &IFlags { + count_bytes: true, + ..IFlags::default() + }, + &matches + ) + .unwrap() + .unwrap() + ); + + // iflag + assert_eq!( + IFlags { + count_bytes: true, + skip_bytes: true, + ..IFlags::default() + }, + parse_iflags(&matches).unwrap() + ); + + // oflag + assert_eq!( + OFlags { + seek_bytes: true, + append: true, + ..OFlags::default() + }, + parse_oflags(&matches).unwrap() + ); +} + // ----- IConvFlags/Output ----- #[test]