From 095ade6621cbe8b33a5225a498f3d5e1609c3092 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20Miguel?= Date: Tue, 6 Apr 2021 03:37:49 -0300 Subject: [PATCH 1/5] Code cleanup --- src/cli.rs | 6 +----- src/evaluator.rs | 1 - src/main.rs | 3 +-- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/cli.rs b/src/cli.rs index 195a8c6..1e646e8 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -2,8 +2,6 @@ use std::{env, ffi::OsString, io, path::PathBuf, vec::Vec}; use oof::{arg_flag, flag}; -use crate::debug; - pub const VERSION: &str = "0.1.5"; #[derive(PartialEq, Eq, Debug)] @@ -87,11 +85,9 @@ pub fn parse_args_from(mut args: Vec) -> crate::Result { // Defaults to decompression when there is no subcommand None => { flags_info.push(arg_flag!('o', "output")); - debug!(&flags_info); - + // Parse flags let (args, mut flags) = oof::filter_flags(args, &flags_info)?; - debug!((&args, &flags)); let files: Vec<_> = args.into_iter().map(PathBuf::from).collect(); // TODO: This line doesn't seem to be working correctly diff --git a/src/evaluator.rs b/src/evaluator.rs index 9d68f5d..b11e96a 100644 --- a/src/evaluator.rs +++ b/src/evaluator.rs @@ -176,7 +176,6 @@ impl Evaluator { let confirm = Confirmation::new("Do you want to overwrite 'FILE'?", Some("FILE")); let (first_compressor, second_compressor) = Self::get_compressor(&output)?; - // TODO: use -y and -n here if output_path.exists() && !utils::permission_for_overwriting(&output_path, flags, &confirm)? { diff --git a/src/main.rs b/src/main.rs index f19879d..bca65fa 100644 --- a/src/main.rs +++ b/src/main.rs @@ -23,7 +23,6 @@ fn main() { } fn run() -> crate::Result<()> { - let ParsedArgs { command, flags } = cli::parse_args()?; - debug!(&command); + let ParsedArgs { command, flags } = cli::parse_args()?; Evaluator::evaluate(command, &flags) } From 9b8dcb40fa5381b88204bbb70f594c253f5170d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20Miguel?= Date: Tue, 6 Apr 2021 04:12:00 -0300 Subject: [PATCH 2/5] cli: Canonicalize input files when decompressing --- src/cli.rs | 39 ++++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/src/cli.rs b/src/cli.rs index 1e646e8..865d3e1 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -1,4 +1,4 @@ -use std::{env, ffi::OsString, io, path::PathBuf, vec::Vec}; +use std::{env, ffi::OsString, path::{Path, PathBuf}, vec::Vec}; use oof::{arg_flag, flag}; @@ -39,8 +39,28 @@ pub struct ParsedArgs { // pub program_called: OsString, // Useful? } -fn canonicalize_files(files: Vec) -> io::Result> { - files.into_iter().map(|path| path.canonicalize()).collect() +fn canonicalize<'a, P>(path: P) -> crate::Result +where + P: AsRef + 'a +{ + match std::fs::canonicalize(&path.as_ref()) { + Ok(abs_path) => Ok(abs_path), + Err(io_err) => { + if !path.as_ref().exists() { + Err(crate::Error::FileNotFound(PathBuf::from(path.as_ref()))) + } else { + eprintln!("{} {}", "[ERROR]", io_err); + Err(crate::Error::IoError) + } + } + } +} + +fn canonicalize_files<'a, P>(files: Vec

) -> crate::Result> +where + P: AsRef + 'a, +{ + files.into_iter().map(canonicalize).collect() } pub fn parse_args_from(mut args: Vec) -> crate::Result { @@ -89,12 +109,17 @@ pub fn parse_args_from(mut args: Vec) -> crate::Result { // Parse flags let (args, mut flags) = oof::filter_flags(args, &flags_info)?; - let files: Vec<_> = args.into_iter().map(PathBuf::from).collect(); - // TODO: This line doesn't seem to be working correctly + let files = args.into_iter().map(canonicalize); + for file in files.clone() { + if let Err(err) = file { + return Err(err); + } + } + let files = files.map(Result::unwrap).collect(); + let output_folder = flags.take_arg("output").map(PathBuf::from); + // TODO: ensure all files are decompressible - // Is the output here fully correct? - // With the paths not canonicalized? let command = Command::Decompress { files, output_folder, From f9272b5ce52b7493cc7a7b3018489f1b426f7362 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20Miguel?= Date: Tue, 6 Apr 2021 04:30:36 -0300 Subject: [PATCH 3/5] evaluator: Verify if input files are decompressible --- src/bytes.rs | 4 +- src/cli.rs | 20 ++++++---- src/compressors/bzip.rs | 2 +- src/compressors/gzip.rs | 2 +- src/compressors/lzma.rs | 2 +- src/compressors/zip.rs | 2 +- src/decompressors/tar.rs | 4 +- src/decompressors/to_memory.rs | 2 +- src/decompressors/zip.rs | 2 +- src/error.rs | 4 +- src/evaluator.rs | 28 +++++++------ src/extension.rs | 10 +++-- src/file.rs | 2 +- src/main.rs | 2 +- src/test.rs | 72 ++++++++++------------------------ src/utils.rs | 13 ++++-- 16 files changed, 81 insertions(+), 90 deletions(-) diff --git a/src/bytes.rs b/src/bytes.rs index ac1be6e..cd7e9b3 100644 --- a/src/bytes.rs +++ b/src/bytes.rs @@ -17,7 +17,7 @@ impl Bytes { impl std::fmt::Display for Bytes { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let num = self.bytes; - debug_assert!(num >= 0.0); + debug_assert!(num >= 0.0); if num < 1_f64 { return write!(f, "{} B", num); } @@ -27,4 +27,4 @@ impl std::fmt::Display for Bytes { write!(f, "{:.2} ", num / delimiter.powi(exponent))?; write!(f, "{}", UNITS[exponent as usize]) } -} \ No newline at end of file +} diff --git a/src/cli.rs b/src/cli.rs index 865d3e1..ef54fe3 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -1,4 +1,9 @@ -use std::{env, ffi::OsString, path::{Path, PathBuf}, vec::Vec}; +use std::{ + env, + ffi::OsString, + path::{Path, PathBuf}, + vec::Vec, +}; use oof::{arg_flag, flag}; @@ -39,9 +44,9 @@ pub struct ParsedArgs { // pub program_called: OsString, // Useful? } -fn canonicalize<'a, P>(path: P) -> crate::Result +fn canonicalize<'a, P>(path: P) -> crate::Result where - P: AsRef + 'a + P: AsRef + 'a, { match std::fs::canonicalize(&path.as_ref()) { Ok(abs_path) => Ok(abs_path), @@ -56,7 +61,7 @@ where } } -fn canonicalize_files<'a, P>(files: Vec

) -> crate::Result> +fn canonicalize_files<'a, P>(files: Vec

) -> crate::Result> where P: AsRef + 'a, { @@ -105,7 +110,7 @@ pub fn parse_args_from(mut args: Vec) -> crate::Result { // Defaults to decompression when there is no subcommand None => { flags_info.push(arg_flag!('o', "output")); - + // Parse flags let (args, mut flags) = oof::filter_flags(args, &flags_info)?; @@ -116,8 +121,9 @@ pub fn parse_args_from(mut args: Vec) -> crate::Result { } } let files = files.map(Result::unwrap).collect(); - + let output_folder = flags.take_arg("output").map(PathBuf::from); + // TODO: ensure all files are decompressible let command = Command::Decompress { @@ -130,4 +136,4 @@ pub fn parse_args_from(mut args: Vec) -> crate::Result { }; Ok(parsed_args) -} \ No newline at end of file +} diff --git a/src/compressors/bzip.rs b/src/compressors/bzip.rs index ab63898..28afd51 100644 --- a/src/compressors/bzip.rs +++ b/src/compressors/bzip.rs @@ -4,8 +4,8 @@ use colored::Colorize; use super::{Compressor, Entry}; use crate::{ - extension::CompressionFormat, bytes::Bytes, + extension::CompressionFormat, file::File, utils::{check_for_multiple_files, ensure_exists}, }; diff --git a/src/compressors/gzip.rs b/src/compressors/gzip.rs index b01208b..a390971 100644 --- a/src/compressors/gzip.rs +++ b/src/compressors/gzip.rs @@ -4,9 +4,9 @@ use colored::Colorize; use super::{Compressor, Entry}; use crate::{ + bytes::Bytes, extension::CompressionFormat, file::File, - bytes::Bytes, utils::{check_for_multiple_files, ensure_exists}, }; diff --git a/src/compressors/lzma.rs b/src/compressors/lzma.rs index d622ac4..71d93c1 100644 --- a/src/compressors/lzma.rs +++ b/src/compressors/lzma.rs @@ -4,9 +4,9 @@ use colored::Colorize; use super::{Compressor, Entry}; use crate::{ + bytes::Bytes, extension::CompressionFormat, file::File, - bytes::Bytes, utils::{check_for_multiple_files, ensure_exists}, }; diff --git a/src/compressors/zip.rs b/src/compressors/zip.rs index 453fbcb..be9f1fe 100644 --- a/src/compressors/zip.rs +++ b/src/compressors/zip.rs @@ -68,7 +68,7 @@ impl ZipCompressor { if entry_path.is_dir() { continue; } - + writer.start_file(entry_path.to_string_lossy(), options)?; println!("Compressing {:?}", entry_path); let file_bytes = std::fs::read(entry.path())?; diff --git a/src/decompressors/tar.rs b/src/decompressors/tar.rs index 2c7ef64..5461b08 100644 --- a/src/decompressors/tar.rs +++ b/src/decompressors/tar.rs @@ -8,13 +8,13 @@ use colored::Colorize; use tar::{self, Archive}; use super::decompressor::{DecompressionResult, Decompressor}; -use crate::{dialogs::Confirmation, file::File, bytes::Bytes, utils}; +use crate::{bytes::Bytes, dialogs::Confirmation, file::File, utils}; #[derive(Debug)] pub struct TarDecompressor {} impl TarDecompressor { - fn unpack_files(from: File, into: &Path, flags: &oof::Flags) -> crate::Result> { + fn unpack_files(from: File, into: &Path, flags: &oof::Flags) -> crate::Result> { println!( "{}: attempting to decompress {:?}", "ouch".bright_blue(), diff --git a/src/decompressors/to_memory.rs b/src/decompressors/to_memory.rs index aa82daf..d7af622 100644 --- a/src/decompressors/to_memory.rs +++ b/src/decompressors/to_memory.rs @@ -6,8 +6,8 @@ use std::{ use colored::Colorize; use super::decompressor::{DecompressionResult, Decompressor}; -use crate::utils; use crate::bytes::Bytes; +use crate::utils; use crate::{extension::CompressionFormat, file::File}; struct DecompressorToMemory {} diff --git a/src/decompressors/zip.rs b/src/decompressors/zip.rs index 7cfabf2..dcf1329 100644 --- a/src/decompressors/zip.rs +++ b/src/decompressors/zip.rs @@ -8,7 +8,7 @@ use colored::Colorize; use zip::{self, read::ZipFile, ZipArchive}; use super::decompressor::{DecompressionResult, Decompressor}; -use crate::{dialogs::Confirmation, file::File, bytes::Bytes, utils}; +use crate::{bytes::Bytes, dialogs::Confirmation, file::File, utils}; #[cfg(unix)] fn __unix_set_permissions(file_path: &Path, file: &ZipFile) { diff --git a/src/error.rs b/src/error.rs index 7752981..6d1c547 100644 --- a/src/error.rs +++ b/src/error.rs @@ -5,7 +5,7 @@ use colored::Colorize; #[derive(PartialEq, Eq)] pub enum Error { UnknownExtensionError(String), - MissingExtensionError(String), + MissingExtensionError(PathBuf), // TODO: get rid of this error variant InvalidUnicode, InvalidInput, @@ -35,7 +35,7 @@ impl fmt::Display for Error { Error::MissingExtensionError(filename) => { write!(f, "{} ", "[ERROR]".red())?; // TODO: show MIME type of the unsupported file - write!(f, "cannot compress to \'{}\', likely because it has an unsupported (or missing) extension.", filename) + write!(f, "cannot compress to {:?}, likely because it has an unsupported (or missing) extension.", filename) } Error::WalkdirError => { // Already printed in the From block diff --git a/src/evaluator.rs b/src/evaluator.rs index b11e96a..697c0f1 100644 --- a/src/evaluator.rs +++ b/src/evaluator.rs @@ -8,20 +8,19 @@ use colored::Colorize; use crate::{ bytes::Bytes, - cli::{VERSION, Command}, + cli::{Command, VERSION}, compressors::{ - Entry, Compressor, BzipCompressor, GzipCompressor, LzmaCompressor, TarCompressor, + BzipCompressor, Compressor, Entry, GzipCompressor, LzmaCompressor, TarCompressor, ZipCompressor, }, decompressors::{ BzipDecompressor, DecompressionResult, Decompressor, GzipDecompressor, LzmaDecompressor, TarDecompressor, ZipDecompressor, - }, - dialogs::Confirmation, - extension::{CompressionFormat, Extension}, - file::File, + }, + dialogs::Confirmation, + extension::{CompressionFormat, Extension}, + file::File, utils, - debug }; pub struct Evaluator {} @@ -33,7 +32,6 @@ impl Evaluator { pub fn get_compressor( file: &File, ) -> crate::Result<(Option, BoxedCompressor)> { - let extension = match &file.extension { Some(extension) => extension.clone(), None => { @@ -213,8 +211,16 @@ impl Evaluator { file_path: &Path, output: Option<&Path>, flags: &oof::Flags, - ) -> crate::Result<()> { - let file = debug!(File::from(file_path)?); + ) -> crate::Result<()> { + // The file to be decompressed + let file = File::from(file_path)?; + // The file must have a supported decompressible format + if file.extension == None { + return Err(crate::Error::MissingExtensionError(PathBuf::from( + file_path, + ))); + } + let output = match output { Some(inner) => Some(File::from(inner)?), None => None, @@ -289,4 +295,4 @@ fn help_message() { println!(" ouch compress output-file"); println!("DECOMPRESSION USAGE:"); println!(" ouch [-o/--output output-folder]"); -} \ No newline at end of file +} diff --git a/src/extension.rs b/src/extension.rs index f8a4029..43e0e1a 100644 --- a/src/extension.rs +++ b/src/extension.rs @@ -57,7 +57,11 @@ impl Extension { (os_str, snd) if os_str.is_empty() => (None, snd), (fst, snd) => (Some(fst), snd), }, - None => return Err(crate::Error::MissingExtensionError(to_utf(file_name))), + None => { + return Err(crate::Error::MissingExtensionError(PathBuf::from( + file_name, + ))) + } }; let (first_ext, second_ext) = match (first_ext, second_ext) { @@ -119,7 +123,7 @@ impl TryFrom<&PathBuf> for CompressionFormat { let ext = match ext.extension() { Some(ext) => ext, None => { - return Err(crate::Error::MissingExtensionError(String::new())); + return Err(crate::Error::MissingExtensionError(PathBuf::new())); } }; extension_from_os_str(ext) @@ -133,7 +137,7 @@ impl TryFrom<&str> for CompressionFormat { let file_name = Path::new(file_name); let ext = match file_name.extension() { Some(ext) => ext, - None => return Err(crate::Error::MissingExtensionError(String::new())), + None => return Err(crate::Error::MissingExtensionError(PathBuf::new())), }; extension_from_os_str(ext) diff --git a/src/file.rs b/src/file.rs index bf29016..a3d2623 100644 --- a/src/file.rs +++ b/src/file.rs @@ -24,7 +24,7 @@ impl<'a> File<'a> { Ok(File { path, contents_in_memory: None, - extension + extension, }) } } diff --git a/src/main.rs b/src/main.rs index bca65fa..984f191 100644 --- a/src/main.rs +++ b/src/main.rs @@ -23,6 +23,6 @@ fn main() { } fn run() -> crate::Result<()> { - let ParsedArgs { command, flags } = cli::parse_args()?; + let ParsedArgs { command, flags } = cli::parse_args()?; Evaluator::evaluate(command, &flags) } diff --git a/src/test.rs b/src/test.rs index 3fc5065..802307d 100644 --- a/src/test.rs +++ b/src/test.rs @@ -27,7 +27,7 @@ where #[cfg(test)] mod argparsing { - use super::{make_dummy_files}; + use super::make_dummy_files; use crate::cli; use crate::cli::Command; use std::{ffi::OsString, fs, path::PathBuf}; @@ -65,10 +65,13 @@ mod argparsing { #[test] fn test_arg_parsing_compress_subcommand() -> crate::Result<()> { - let files = vec!["a", "b", "c"]; make_dummy_files(&*files)?; - let files= files.iter().map(fs::canonicalize).map(Result::unwrap).collect(); + let files = files + .iter() + .map(fs::canonicalize) + .map(Result::unwrap) + .collect(); let expected = Command::Compress { files, @@ -107,70 +110,37 @@ mod argparsing { mod byte_pretty_printing { use crate::bytes::Bytes; #[test] - fn bytes () { - assert_eq!( - &format!("{}", Bytes::new(234)), - "234.00 B" - ); + fn bytes() { + assert_eq!(&format!("{}", Bytes::new(234)), "234.00 B"); - assert_eq!( - &format!("{}", Bytes::new(999)), - "999.00 B" - ); + assert_eq!(&format!("{}", Bytes::new(999)), "999.00 B"); } #[test] - fn kilobytes () { - assert_eq!( - &format!("{}", Bytes::new(2234)), - "2.23 kB" - ); + fn kilobytes() { + assert_eq!(&format!("{}", Bytes::new(2234)), "2.23 kB"); - assert_eq!( - &format!("{}", Bytes::new(62500)), - "62.50 kB" - ); + assert_eq!(&format!("{}", Bytes::new(62500)), "62.50 kB"); - assert_eq!( - &format!("{}", Bytes::new(329990)), - "329.99 kB" - ); + assert_eq!(&format!("{}", Bytes::new(329990)), "329.99 kB"); } #[test] - fn megabytes () { - assert_eq!( - &format!("{}", Bytes::new(2750000)), - "2.75 MB" - ); + fn megabytes() { + assert_eq!(&format!("{}", Bytes::new(2750000)), "2.75 MB"); - assert_eq!( - &format!("{}", Bytes::new(55000000)), - "55.00 MB" - ); + assert_eq!(&format!("{}", Bytes::new(55000000)), "55.00 MB"); - assert_eq!( - &format!("{}", Bytes::new(987654321)), - "987.65 MB" - ); + assert_eq!(&format!("{}", Bytes::new(987654321)), "987.65 MB"); } #[test] - fn gigabytes () { - assert_eq!( - &format!("{}", Bytes::new(5280000000)), - "5.28 GB" - ); + fn gigabytes() { + assert_eq!(&format!("{}", Bytes::new(5280000000)), "5.28 GB"); - assert_eq!( - &format!("{}", Bytes::new(95200000000)), - "95.20 GB" - ); + assert_eq!(&format!("{}", Bytes::new(95200000000)), "95.20 GB"); - assert_eq!( - &format!("{}", Bytes::new(302000000000)), - "302.00 GB" - ); + assert_eq!(&format!("{}", Bytes::new(302000000000)), "302.00 GB"); } } diff --git a/src/utils.rs b/src/utils.rs index 1276ddf..3b6d4d1 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -12,16 +12,19 @@ use crate::{dialogs::Confirmation, extension::CompressionFormat, file::File}; #[macro_export] #[cfg(debug_assertions)] macro_rules! debug { - ($x:expr) => { dbg!($x) } + ($x:expr) => { + dbg!($x) + }; } #[macro_export] #[cfg(not(debug_assertions))] macro_rules! debug { - ($x:expr) => { std::convert::identity($x) } + ($x:expr) => { + std::convert::identity($x) + }; } - pub(crate) fn ensure_exists<'a, P>(path: P) -> crate::Result<()> where P: AsRef + 'a, @@ -82,7 +85,9 @@ pub(crate) fn change_dir_and_return_parent(filename: &Path) -> crate::Result Date: Tue, 6 Apr 2021 04:44:08 -0300 Subject: [PATCH 4/5] Fix `cargo test` --- .gitignore | 2 ++ src/test.rs | 13 ++++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 767dae2..2c748b5 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,8 @@ # will have compiled files and executables target/ +makeshift_testing.py + # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html Cargo.lock diff --git a/src/test.rs b/src/test.rs index 802307d..d4115e7 100644 --- a/src/test.rs +++ b/src/test.rs @@ -86,23 +86,30 @@ mod argparsing { } #[test] - fn test_arg_parsing_decompress_subcommand() { + fn test_arg_parsing_decompress_subcommand() -> crate::Result<()> { + let files = vec!["a", "b", "c"]; + make_dummy_files(&*files)?; let files: Vec<_> = ["a", "b", "c"].iter().map(PathBuf::from).collect(); let expected = Command::Decompress { - files: files.clone(), + files: files.iter().filter_map(|p| fs::canonicalize(p).ok()).collect(), output_folder: None, }; assert_eq!(expected, parse!("a b c").command); let expected = Command::Decompress { - files, + files: files.iter().map(fs::canonicalize).map(Result::unwrap).collect(), output_folder: Some("folder".into()), }; assert_eq!(expected, parse!("a b c --output folder").command); assert_eq!(expected, parse!("a b --output folder c").command); assert_eq!(expected, parse!("a --output folder b c").command); assert_eq!(expected, parse!("--output folder a b c").command); + + fs::remove_file("a")?; + fs::remove_file("b")?; + fs::remove_file("c")?; + Ok(()) } } From 249e9959fc0eb7b1c571ee964edb62bfa635ff92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20Miguel?= Date: Tue, 6 Apr 2021 12:51:53 -0300 Subject: [PATCH 5/5] Fix failing test --- src/test.rs | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/src/test.rs b/src/test.rs index d4115e7..4d61540 100644 --- a/src/test.rs +++ b/src/test.rs @@ -87,28 +87,39 @@ mod argparsing { #[test] fn test_arg_parsing_decompress_subcommand() -> crate::Result<()> { - let files = vec!["a", "b", "c"]; + let files = vec!["d", "e", "f"]; make_dummy_files(&*files)?; - let files: Vec<_> = ["a", "b", "c"].iter().map(PathBuf::from).collect(); + + let files: Vec<_> = files.iter().map(PathBuf::from).collect(); let expected = Command::Decompress { - files: files.iter().filter_map(|p| fs::canonicalize(p).ok()).collect(), + files: files + .iter() + .map(fs::canonicalize) + .map(Result::unwrap) + .collect(), output_folder: None, }; - assert_eq!(expected, parse!("a b c").command); + + assert_eq!(expected, parse!("d e f").command); let expected = Command::Decompress { files: files.iter().map(fs::canonicalize).map(Result::unwrap).collect(), output_folder: Some("folder".into()), }; - assert_eq!(expected, parse!("a b c --output folder").command); - assert_eq!(expected, parse!("a b --output folder c").command); - assert_eq!(expected, parse!("a --output folder b c").command); - assert_eq!(expected, parse!("--output folder a b c").command); + assert_eq!(expected, parse!("d e f --output folder").command); + assert_eq!(expected, parse!("d e --output folder f").command); + assert_eq!(expected, parse!("d --output folder e f").command); + assert_eq!(expected, parse!("--output folder d e f").command); - fs::remove_file("a")?; - fs::remove_file("b")?; - fs::remove_file("c")?; + assert_eq!(expected, parse!("d e f -o folder").command); + assert_eq!(expected, parse!("d e -o folder f").command); + assert_eq!(expected, parse!("d -o folder e f").command); + assert_eq!(expected, parse!("-o folder d e f").command); + + fs::remove_file("d")?; + fs::remove_file("e")?; + fs::remove_file("f")?; Ok(()) } }