use crate::options::parser::MatchedFlags;
use crate::options::{flags, NumberSource, OptionsError};
use crate::fs::dir_action::{DirAction, RecurseOptions};
impl DirAction {
pub fn deduce(matches: &MatchedFlags<'_>, can_tree: bool) -> Result<Self, OptionsError> {
let recurse = matches.has(&flags::RECURSE)?;
let as_file =
matches.has(&flags::TREAT_DIRS_AS_FILES)? || matches.has(&flags::LIST_DIRS)?;
let tree = matches.has(&flags::TREE)?;
if matches.is_strict() {
if !recurse && !tree && matches.count(&flags::LEVEL) > 0 {
return Err(OptionsError::Useless2(
&flags::LEVEL,
&flags::RECURSE,
&flags::TREE,
));
} else if recurse && as_file {
return Err(OptionsError::Conflict(
&flags::RECURSE,
&flags::TREAT_DIRS_AS_FILES,
));
} else if tree && as_file {
return Err(OptionsError::Conflict(
&flags::TREE,
&flags::TREAT_DIRS_AS_FILES,
));
}
}
if tree && can_tree {
Ok(Self::Recurse(RecurseOptions::deduce(matches, true)?))
} else if recurse {
Ok(Self::Recurse(RecurseOptions::deduce(matches, false)?))
} else if as_file {
Ok(Self::AsFile)
} else {
Ok(Self::List)
}
}
}
impl RecurseOptions {
pub fn deduce(matches: &MatchedFlags<'_>, tree: bool) -> Result<Self, OptionsError> {
if let Some(level) = matches.get(&flags::LEVEL)? {
let arg_str = level.to_string_lossy();
match arg_str.parse() {
Ok(l) => Ok(Self {
tree,
max_depth: Some(l),
}),
Err(e) => {
let source = NumberSource::Arg(&flags::LEVEL);
Err(OptionsError::FailedParse(arg_str.to_string(), source, e))
}
}
} else {
Ok(Self {
tree,
max_depth: None,
})
}
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::options::flags;
use crate::options::parser::Flag;
macro_rules! test {
($name:ident: $type:ident <- $inputs:expr; $stricts:expr => $result:expr) => {
#[test]
fn $name() {
use crate::options::parser::Arg;
use crate::options::test::parse_for_test;
use crate::options::test::Strictnesses::*;
static TEST_ARGS: &[&Arg] = &[
&flags::RECURSE,
&flags::TREAT_DIRS_AS_FILES,
&flags::TREE,
&flags::LEVEL,
];
for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| {
$type::deduce(mf, true)
}) {
assert_eq!(result, $result);
}
}
};
}
test!(empty: DirAction <- []; Both => Ok(DirAction::List));
test!(dirs_short: DirAction <- ["-d"]; Both => Ok(DirAction::AsFile));
test!(dirs_long: DirAction <- ["--treat-dirs-as-files"]; Both => Ok(DirAction::AsFile));
use self::DirAction::Recurse;
test!(rec_short: DirAction <- ["-R"]; Both => Ok(Recurse(RecurseOptions { tree: false, max_depth: None })));
test!(rec_long: DirAction <- ["--recurse"]; Both => Ok(Recurse(RecurseOptions { tree: false, max_depth: None })));
test!(rec_lim_short: DirAction <- ["-RL4"]; Both => Ok(Recurse(RecurseOptions { tree: false, max_depth: Some(4) })));
test!(rec_lim_short_2: DirAction <- ["-RL=5"]; Both => Ok(Recurse(RecurseOptions { tree: false, max_depth: Some(5) })));
test!(rec_lim_long: DirAction <- ["--recurse", "--level", "666"]; Both => Ok(Recurse(RecurseOptions { tree: false, max_depth: Some(666) })));
test!(rec_lim_long_2: DirAction <- ["--recurse", "--level=0118"]; Both => Ok(Recurse(RecurseOptions { tree: false, max_depth: Some(118) })));
test!(tree: DirAction <- ["--tree"]; Both => Ok(Recurse(RecurseOptions { tree: true, max_depth: None })));
test!(rec_tree: DirAction <- ["--recurse", "--tree"]; Both => Ok(Recurse(RecurseOptions { tree: true, max_depth: None })));
test!(rec_short_tree: DirAction <- ["-TR"]; Both => Ok(Recurse(RecurseOptions { tree: true, max_depth: None })));
test!(dirs_recurse: DirAction <- ["--treat-dirs-as-files", "--recurse"]; Last => Ok(Recurse(RecurseOptions { tree: false, max_depth: None })));
test!(dirs_tree: DirAction <- ["--treat-dirs-as-files", "--tree"]; Last => Ok(Recurse(RecurseOptions { tree: true, max_depth: None })));
test!(just_level: DirAction <- ["--level=4"]; Last => Ok(DirAction::List));
test!(dirs_recurse_2: DirAction <- ["--treat-dirs-as-files", "--recurse"]; Complain => Err(OptionsError::Conflict(&flags::RECURSE, &flags::TREAT_DIRS_AS_FILES)));
test!(dirs_tree_2: DirAction <- ["--treat-dirs-as-files", "--tree"]; Complain => Err(OptionsError::Conflict(&flags::TREE, &flags::TREAT_DIRS_AS_FILES)));
test!(just_level_2: DirAction <- ["--level=4"]; Complain => Err(OptionsError::Useless2(&flags::LEVEL, &flags::RECURSE, &flags::TREE)));
test!(overriding_1: DirAction <- ["-RL=6", "-L=7"]; Last => Ok(Recurse(RecurseOptions { tree: false, max_depth: Some(7) })));
test!(overriding_2: DirAction <- ["-RL=6", "-L=7"]; Complain => Err(OptionsError::Duplicate(Flag::Short(b'L'), Flag::Short(b'L'))));
}