diff --git a/src/cli.rs b/src/cli.rs index ee50bb0..75daad7 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -1,13 +1,13 @@ use std::{convert::TryFrom, ffi::OsStr, path::PathBuf, vec::Vec}; -use clap::{Arg}; +use clap::{Arg, Values}; use colored::Colorize; use crate::error; use crate::extensions::CompressionExtension; use crate::file::File; -#[derive(Debug)] +#[derive(PartialEq, Eq, Debug)] pub enum CommandType { Compression( // Files to be compressed @@ -19,13 +19,13 @@ pub enum CommandType { ), } -#[derive(Debug)] +#[derive(PartialEq, Eq, Debug)] pub struct Command { pub command_type: CommandType, pub output: Option, } -pub fn get_matches() -> clap::ArgMatches<'static> { +pub fn clap_app<'a, 'b>() -> clap::App<'a, 'b> { clap::App::new("ouch") .version("0.1.0") .about("ouch is a unified compression & decompression utility") @@ -53,7 +53,10 @@ pub fn get_matches() -> clap::ArgMatches<'static> { .help("Output file (TODO description)") .takes_value(true), ) - .get_matches() +} + +pub fn get_matches() -> clap::ArgMatches<'static> { + clap_app().get_matches() } // holy spaghetti code @@ -62,24 +65,42 @@ impl TryFrom> for Command { type Error = error::Error; fn try_from(matches: clap::ArgMatches<'static>) -> error::OuchResult { + + let process_decompressible_input = |input_files: Values| { + let input_files = input_files + .map(|filename| (filename, CompressionExtension::try_from(filename))); + + for file in input_files.clone() { + if let (file, Err(_)) = file { + // eprintln!("{}: file '{}' is not decompressible.", "error".red(), file); + return Err(error::Error::InputsMustHaveBeenDecompressible(file.into())); + } + } + + + Ok(input_files + .map(|(filename, extension)| + (PathBuf::from(filename), extension.unwrap()) + ) + .collect::>()) + }; + // Possibilities: // * Case 1: output not supplied, therefore try to infer output by checking if all input files are decompressible // * Case 2: output supplied let output_was_supplied = matches.is_present("output"); + + let input_files = matches + .values_of("input") + .unwrap(); // Safe to unwrap since input is an obligatory argument + if output_was_supplied { let output_file = matches .value_of("output") .unwrap(); // Safe unwrap since we've established that output was supplied - let input_files = matches - .values_of("input") - .unwrap(); // Safe to unwrap since input is an obligatory argument - // .map(PathBuf::from) - // .collect(); - - let output_file_extension = CompressionExtension::try_from(output_file); let output_is_compressible = output_file_extension.is_ok(); if output_is_compressible { @@ -99,22 +120,8 @@ impl TryFrom> for Command { } else { // Checking if input files are decompressible - let input_files = input_files - .map(|filename| (filename, CompressionExtension::try_from(filename))); - for file in input_files.clone() { - if let (file, Err(_)) = file { - // eprintln!("{}: file '{}' is not decompressible.", "error".red(), file); - return Err(error::Error::InputsMustHaveBeenDecompressible(file.into())); - } - } - - let input_files = - input_files - .map(|(filename, extension)| - (PathBuf::from(filename), extension.unwrap()) - ) - .collect(); + let input_files = process_decompressible_input(input_files)?; println!("{}: attempting to decompress input files into {}", "info".yellow(), output_file); return Ok( @@ -125,94 +132,17 @@ impl TryFrom> for Command { ); } } else { - // BIG TODO - Err(error::Error::MissingExtensionError("placeholder result".into())) + // else: output file not supplied + // Case 1: all input files are decompressible + // Case 2: error + let input_files = process_decompressible_input(input_files)?; + return Ok( + Command { + command_type: CommandType::Decompression(input_files), + output: None + } + ); + } } -} - -// impl TryFrom> for ArgValues { -// type Error = error::OuchError; -// fn try_from(matches: clap::ArgMatches<'static>) -> error::OuchResult { -// // Case 1: -o was set -// // Case 1.1: -o was set and has a (supported) compression file extension -// // |--> Compress all input files into the supplied output file (no extension checks on inputs) -// // Case 1.2: -o was set and is not a supported expression -// // Case 2: -o was not set -// // Case 2.1: -o was not set and all input files are (supported) compression file extensions -// // |--> Decompress input files into inferred filenames or directories -// // Case 2.2: -o was not set and not all input files are (supported) compression file extensions -// // |--> Issue an error - -// let inputs = matches -// .values_of("input") -// .unwrap() // Safe to unwrap since this is a required argument -// .map(|input: &str| { -// ( -// PathBuf::from(input), -// CompressionExtension::try_from(input).ok(), -// ) -// }); - -// let output_was_supplied = matches.is_present("output"); -// let inputs_are_compressed_files = inputs.clone().all(|(_, ext)| ext.is_some()); - -// match (output_was_supplied, inputs_are_compressed_files) { -// (true, true) => { -// // -o was set and inputs are all valid compressed files - -// let output = matches.value_of("output").unwrap(); -// let output = PathBuf::from(output); -// match CompressionExtension::try_from(&output) { -// Ok(ext) => { -// // If the output file is a valid compressed file, then we compress the input files into it -// Ok(Self { -// command_type: CommandType::Compress( -// inputs.map(|(path, _)| path).collect(), -// ), -// output: Some((output, ext)), -// }) -// } -// Err(_) => { -// // If the output file is not a compressed file, then we decompress the input files into it -// Ok(Self { -// command_type: CommandType::Decompress( -// inputs.map(|(path, ext)| (path, ext.unwrap())).collect(), -// ), -// output: Some((output, CompressionExtension::NotCompressed)), -// }) -// } -// } -// } -// (true, false) => { -// // -o was set and inputs are not (all) valid compressed files -// let output_str = matches.value_of("output").unwrap(); -// let output = PathBuf::from(output_str); -// let output_ext = match CompressionExtension::try_from(&output) { -// Ok(ext) => ext, -// Err(_) => { -// return Err(error::OuchError::MissingExtensionError(output_str.into())); -// } -// }; - -// Ok(Self { -// command_type: CommandType::Compress(inputs.map(|(path, _)| path).collect()), -// output: Some((output, output_ext)), -// }) -// } -// (false, true) => { -// // Case 2.1: -o was not set and all input files are (supported) compression file extensions -// Ok(Self { -// command_type: CommandType::Decompress( -// inputs.map(|(path, ext)| (path, ext.unwrap())).collect(), -// ), -// output: None, -// }) -// } -// (false, false) => { -// // Case 2.2: -o was not set and not all input files are not (supported) compression file extensions -// Err(error::OuchError::InvalidInput) -// } -// } -// } -// } \ No newline at end of file +} \ No newline at end of file diff --git a/src/extensions.rs b/src/extensions.rs index dc85008..e4afb80 100644 --- a/src/extensions.rs +++ b/src/extensions.rs @@ -4,7 +4,7 @@ use std::{ }; use crate::error; -#[derive(Debug)] +#[derive(PartialEq, Eq, Debug)] /// Accepted extensions for input and output pub enum CompressionExtension { // .gz diff --git a/src/file.rs b/src/file.rs index 325e8ba..89e7399 100644 --- a/src/file.rs +++ b/src/file.rs @@ -12,7 +12,7 @@ use crate::extensions::CompressionExtension; // pub filename: PathBuf, // } -#[derive(Debug)] +#[derive(PartialEq, Eq, Debug)] pub enum File { WithExtension((PathBuf, CompressionExtension)), WithoutExtension(PathBuf) diff --git a/src/main.rs b/src/main.rs index 34e9a50..e04b98e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,6 +6,7 @@ mod cli; mod file; mod extensions; mod error; +mod test; fn main() { diff --git a/src/test.rs b/src/test.rs index e69de29..3f523d5 100644 --- a/src/test.rs +++ b/src/test.rs @@ -0,0 +1,64 @@ +#[cfg(test)] +mod cli { + + use std::{convert::TryFrom}; + + use crate::cli::clap_app; + use crate::cli::Command; + use crate::file::File; + use crate::cli::CommandType::*; + use crate::extensions::CompressionExtension::*; + use crate::error::OuchResult; + + #[test] + fn decompress_files_into_folder() -> OuchResult<()> { + let matches = clap_app(). + get_matches_from( + vec!["ouch", "-i", "file.zip", "-o", "folder/"] + ); + let command_from_matches = Command::try_from(matches)?; + + assert_eq!( + command_from_matches, + Command { + command_type: Decompression( + vec![ + ( + "file.zip".into(), + Zip, + ), + ], + ), + output: Some(File::WithoutExtension("folder".into())), + } + ); + + Ok(()) + } + + #[test] + fn decompress_files() -> OuchResult<()> { + let matches = clap_app(). + get_matches_from( + vec!["ouch", "-i", "file.zip"] + ); + let command_from_matches = Command::try_from(matches)?; + + assert_eq!( + command_from_matches, + Command { + command_type: Decompression( + vec![ + ( + "file.zip".into(), + Zip, + ), + ], + ), + output: None, + } + ); + + Ok(()) + } +} \ No newline at end of file