use crate::cli::cli::Cli;
use crate::cli::file::FileKind;
use crate::cli::hidden::HiddenKind;
use crate::cli::order::OrderKind;
use crate::cli::recent::RecentKind;
use crate::error::MyResult;
use crate::git::flags::GitFlags;
use chrono::{DateTime, TimeZone, Utc};
use clap_builder::{ColorChoice, Parser};
use clap_complete::Shell;
use std::collections::HashSet;
#[derive(Default)]
pub struct Config {
cli: Cli,
piped: bool,
curr_time: DateTime<Utc>,
sort_order: Vec<OrderKind>,
sort_name: bool,
}
impl Config {
pub fn new<G: Fn() -> DateTime<Utc>>(
args: Vec<String>,
piped: bool,
factory: G,
) -> MyResult<Self> {
let mut cli = Cli::try_parse_from(args)?;
let piped = piped && !cli.terminal();
let curr_time = cli.curr_time(factory);
let (sort_order, sort_name) = cli.sort_order();
let config = Self { cli, piped, curr_time, sort_order, sort_name };
Ok(config)
}
pub fn curr_time(&self) -> &DateTime<Utc> {
&self.curr_time
}
pub fn min_depth(&self) -> Option<usize> {
self.cli.min_depth()
}
pub fn max_depth(&self) -> Option<usize> {
self.cli.max_depth()
}
pub fn show_indent(&self) -> bool {
self.cli.show_indent
}
pub fn show_hidden(&self) -> HiddenKind {
match self.cli.show_hidden {
0 => HiddenKind::None,
1 => HiddenKind::Files,
_ => HiddenKind::Recurse,
}
}
pub fn zip_expand(&self) -> bool {
self.cli.zip_expand
}
pub fn zip_password(&self) -> &Option<String> {
&self.cli.zip_password
}
pub fn case_sensitive(&self) -> Option<bool> {
if self.cli.case_sensitive {
Some(true)
} else if self.cli.case_insensitive {
Some(false)
} else {
None
}
}
pub fn sort_order(&self) -> &Vec<OrderKind> {
&self.sort_order
}
pub fn sort_name(&self) -> bool {
self.sort_name
}
pub fn filter_recent(&self) -> RecentKind {
self.cli.filter_recent.unwrap_or_default()
}
pub fn filter_types(&self) -> Option<&HashSet<FileKind>> {
self.cli.filter_types.as_ref().map(|x| &x.inner)
}
pub fn filter_git(&self) -> Option<&GitFlags> {
self.cli.filter_git.as_ref()
}
#[cfg(debug_assertions)]
pub fn show_debug(&self) -> bool {
self.cli.show_debug
}
pub fn show_precise(&self) -> bool {
self.cli.show_precise
}
pub fn show_utc(&self) -> bool {
self.cli.show_utc
}
pub fn show_total(&self) -> bool {
self.cli.show_total
}
#[cfg(unix)]
pub fn show_owner(&self) -> bool {
self.cli.show_owner
}
pub fn show_sig(&self) -> bool {
self.cli.show_sig
}
pub fn only_path(&self) -> bool {
if self.cli.null_path {
true
} else {
match self.cli.only_path {
0 => self.piped,
1 => true,
_ => false,
}
}
}
pub fn escape_path(&self) -> bool {
if self.cli.null_path {
false
} else {
match self.cli.only_path {
0 => self.piped,
1 => false,
_ => false,
}
}
}
pub fn null_path(&self) -> bool {
self.cli.null_path
}
pub fn abs_path(&self) -> bool {
self.cli.abs_path
}
#[cfg(windows)]
pub fn win_path(&self) -> bool {
self.cli.win_path
}
#[cfg(windows)]
pub fn win_ver(&self) -> bool {
self.cli.win_ver
}
pub fn color(&self) -> Option<ColorChoice> {
self.cli.color
}
pub fn quiet(&self) -> bool {
self.cli.quiet
}
pub fn completion(&self) -> Option<Shell> {
self.cli.completion
}
pub fn patterns(&self) -> &Vec<String> {
&self.cli.patterns
}
pub fn start_time<Tz: TimeZone>(&self, zone: &Tz) -> Option<DateTime<Utc>> {
self.filter_recent().subtract_from(self.curr_time(), zone)
}
#[cfg(windows)]
pub fn want_decrypt(&self) -> bool {
self.show_sig() || self.win_ver()
}
#[cfg(not(windows))]
pub fn want_decrypt(&self) -> bool {
self.show_sig()
}
}
#[cfg(test)]
mod tests {
use crate::cli::file::{ExecKind, FileKind, FileSet};
use crate::cli::hidden::HiddenKind;
use crate::cli::order::DirKind;
use crate::cli::recent::RecentKind;
use crate::config::{Config, OrderKind};
use crate::git::flags::GitFlags;
use chrono::{DateTime, NaiveDate, NaiveDateTime, NaiveTime, TimeZone, Utc};
use pretty_assertions::assert_eq;
use std::collections::HashSet;
use std::hash::Hash;
#[test]
fn test_depth_is_handled() {
let args = vec!["ex"];
let config = create_config(args);
assert_eq!(Some(1), config.min_depth());
assert_eq!(Some(1), config.max_depth());
let args = vec!["ex", "-d4"];
let config = create_config(args);
assert_eq!(Some(1), config.min_depth());
assert_eq!(Some(5), config.max_depth());
let args = vec!["ex", "-d-4"];
let config = create_config(args);
assert_eq!(Some(1), config.min_depth());
assert_eq!(Some(5), config.max_depth());
let args = vec!["ex", "-d2-4"];
let config = create_config(args);
assert_eq!(Some(3), config.min_depth());
assert_eq!(Some(5), config.max_depth());
let args = vec!["ex", "-d2-"];
let config = create_config(args);
assert_eq!(Some(3), config.min_depth());
assert_eq!(None, config.max_depth());
let args = vec!["ex", "-s"];
let config = create_config(args);
assert_eq!(Some(1), config.min_depth());
assert_eq!(None, config.max_depth());
let args = vec!["ex", "-s", "-d4"];
let config = create_config(args);
assert_eq!(Some(1), config.min_depth());
assert_eq!(None, config.max_depth());
let args = vec!["ex", "--recurse"];
let config = create_config(args);
assert_eq!(Some(1), config.min_depth());
assert_eq!(None, config.max_depth());
let args = vec!["ex", "--depth=4"];
let config = create_config(args);
assert_eq!(Some(1), config.min_depth());
assert_eq!(Some(5), config.max_depth());
}
#[test]
fn test_indent_is_handled() {
let args = vec!["ex"];
let config = create_config(args);
assert_eq!(false, config.show_indent());
let args = vec!["ex", "-i"];
let config = create_config(args);
assert_eq!(true, config.show_indent());
let args = vec!["ex", "--indent"];
let config = create_config(args);
assert_eq!(true, config.show_indent());
}
#[test]
fn test_all_files_is_handled() {
let args = vec!["ex"];
let config = create_config(args);
assert_eq!(HiddenKind::None, config.show_hidden());
let args = vec!["ex", "-a"];
let config = create_config(args);
assert_eq!(HiddenKind::Files, config.show_hidden());
let args = vec!["ex", "-aa"];
let config = create_config(args);
assert_eq!(HiddenKind::Recurse, config.show_hidden());
let args = vec!["ex", "-a", "-a"];
let config = create_config(args);
assert_eq!(HiddenKind::Recurse, config.show_hidden());
let args = vec!["ex", "--all-files"];
let config = create_config(args);
assert_eq!(HiddenKind::Files, config.show_hidden());
}
#[test]
fn test_zip_is_handled() {
let args = vec!["ex"];
let config = create_config(args);
assert_eq!(false, config.zip_expand());
let args = vec!["ex", "-z"];
let config = create_config(args);
assert_eq!(true, config.zip_expand());
let args = vec!["ex", "--zip"];
let config = create_config(args);
assert_eq!(true, config.zip_expand());
}
#[test]
fn test_password_is_handled() {
let args = vec!["ex"];
let config = create_config(args);
assert_eq!(&None, config.zip_password());
let args = vec!["ex", "--password", "secret"];
let config = create_config(args);
assert_eq!(&Some(String::from("secret")), config.zip_password());
}
#[test]
fn test_case_is_handled() {
let args = vec!["ex"];
let config = create_config(args);
assert_eq!(None, config.case_sensitive());
let args = vec!["ex", "--case"];
let config = create_config(args);
assert_eq!(Some(true), config.case_sensitive());
let args = vec!["ex", "--case", "--no-case"];
let config = create_config(args);
assert_eq!(Some(false), config.case_sensitive());
let args = vec!["ex", "--no-case"];
let config = create_config(args);
assert_eq!(Some(false), config.case_sensitive());
let args = vec!["ex", "--no-case", "--case"];
let config = create_config(args);
assert_eq!(Some(true), config.case_sensitive());
}
#[test]
fn test_order_is_handled() {
let expected = vec![OrderKind::Group, OrderKind::Dir, OrderKind::Name];
let args = vec!["ex"];
let config = create_config(args);
assert_eq!(&expected, config.sort_order());
assert_eq!(false, config.sort_name());
let expected = vec![OrderKind::Dir, OrderKind::Name];
let args = vec!["ex", "-od"];
let config = create_config(args);
assert_eq!(&expected, config.sort_order());
assert_eq!(false, config.sort_name());
let expected = vec![OrderKind::Name, OrderKind::Dir];
let args = vec!["ex", "-on"];
let config = create_config(args);
assert_eq!(&expected, config.sort_order());
assert_eq!(true, config.sort_name());
let expected = vec![OrderKind::Ext, OrderKind::Dir, OrderKind::Name];
let args = vec!["ex", "-oe"];
let config = create_config(args);
assert_eq!(&expected, config.sort_order());
assert_eq!(false, config.sort_name());
let expected = vec![OrderKind::Size(DirKind::Asc), OrderKind::Dir, OrderKind::Name];
let args = vec!["ex", "-os"];
let config = create_config(args);
assert_eq!(&expected, config.sort_order());
assert_eq!(false, config.sort_name());
let expected = vec![OrderKind::Size(DirKind::Asc), OrderKind::Dir, OrderKind::Name];
let args = vec!["ex", "-os+"];
let config = create_config(args);
assert_eq!(&expected, config.sort_order());
assert_eq!(false, config.sort_name());
let expected = vec![OrderKind::Size(DirKind::Desc), OrderKind::Dir, OrderKind::Name];
let args = vec!["ex", "-os-"];
let config = create_config(args);
assert_eq!(&expected, config.sort_order());
assert_eq!(false, config.sort_name());
let expected = vec![OrderKind::Time(DirKind::Asc), OrderKind::Dir, OrderKind::Name];
let args = vec!["ex", "-ot"];
let config = create_config(args);
assert_eq!(&expected, config.sort_order());
assert_eq!(false, config.sort_name());
let expected = vec![OrderKind::Time(DirKind::Asc), OrderKind::Dir, OrderKind::Name];
let args = vec!["ex", "-ot+"];
let config = create_config(args);
assert_eq!(&expected, config.sort_order());
assert_eq!(false, config.sort_name());
let expected = vec![OrderKind::Time(DirKind::Desc), OrderKind::Dir, OrderKind::Name];
let args = vec!["ex", "-ot-"];
let config = create_config(args);
assert_eq!(&expected, config.sort_order());
assert_eq!(false, config.sort_name());
let expected = vec![OrderKind::Dir, OrderKind::Ext, OrderKind::Size(DirKind::Asc), OrderKind::Time(DirKind::Asc), OrderKind::Name];
let args = vec!["ex", "--order=dest"];
let config = create_config(args);
assert_eq!(&expected, config.sort_order());
assert_eq!(false, config.sort_name());
let expected = vec![OrderKind::Ext, OrderKind::Size(DirKind::Asc), OrderKind::Time(DirKind::Asc), OrderKind::Dir, OrderKind::Name];
let args = vec!["ex", "--order=est"];
let config = create_config(args);
assert_eq!(&expected, config.sort_order());
assert_eq!(false, config.sort_name());
let expected = vec![OrderKind::Ext, OrderKind::Size(DirKind::Asc), OrderKind::Time(DirKind::Asc), OrderKind::Dir, OrderKind::Name];
let args = vec!["ex", "--order=e+s+t+"];
let config = create_config(args);
assert_eq!(&expected, config.sort_order());
assert_eq!(false, config.sort_name());
let expected = vec![OrderKind::Ext, OrderKind::Size(DirKind::Desc), OrderKind::Time(DirKind::Desc), OrderKind::Dir, OrderKind::Name];
let args = vec!["ex", "--order=e-s-t-"];
let config = create_config(args);
assert_eq!(&expected, config.sort_order());
assert_eq!(false, config.sort_name());
}
#[test]
fn test_order_defaults_to_group_with_no_recursion() {
let expected = vec![OrderKind::Group, OrderKind::Dir, OrderKind::Name];
let args = vec!["ex"];
let config = create_config(args);
assert_eq!(&expected, config.sort_order());
assert_eq!(false, config.sort_name());
let expected = vec![OrderKind::Group, OrderKind::Dir, OrderKind::Name];
let args = vec!["ex", "-d0"];
let config = create_config(args);
assert_eq!(&expected, config.sort_order());
assert_eq!(false, config.sort_name());
let expected = vec![OrderKind::Dir, OrderKind::Name];
let args = vec!["ex", "-d1"];
let config = create_config(args);
assert_eq!(&expected, config.sort_order());
assert_eq!(false, config.sort_name());
let expected = vec![OrderKind::Dir, OrderKind::Name];
let args = vec!["ex", "-d2"];
let config = create_config(args);
assert_eq!(&expected, config.sort_order());
assert_eq!(false, config.sort_name());
let expected = vec![OrderKind::Dir, OrderKind::Name];
let args = vec!["ex", "-s"];
let config = create_config(args);
assert_eq!(&expected, config.sort_order());
assert_eq!(false, config.sort_name());
let expected = vec![OrderKind::Ext, OrderKind::Dir, OrderKind::Name];
let args = vec!["ex", "-oe"];
let config = create_config(args);
assert_eq!(&expected, config.sort_order());
assert_eq!(false, config.sort_name());
let expected = vec![OrderKind::Ext, OrderKind::Dir, OrderKind::Name];
let args = vec!["ex", "-oe", "-d0"];
let config = create_config(args);
assert_eq!(&expected, config.sort_order());
assert_eq!(false, config.sort_name());
let expected = vec![OrderKind::Ext, OrderKind::Dir, OrderKind::Name];
let args = vec!["ex", "-oe", "-d1"];
let config = create_config(args);
assert_eq!(&expected, config.sort_order());
assert_eq!(false, config.sort_name());
let expected = vec![OrderKind::Ext, OrderKind::Dir, OrderKind::Name];
let args = vec!["ex", "-oe", "-d2"];
let config = create_config(args);
assert_eq!(&expected, config.sort_order());
assert_eq!(false, config.sort_name());
let expected = vec![OrderKind::Ext, OrderKind::Dir, OrderKind::Name];
let args = vec!["ex", "-oe", "-s"];
let config = create_config(args);
assert_eq!(&expected, config.sort_order());
assert_eq!(false, config.sort_name());
}
#[test]
fn test_order_defaults_to_directory_with_indent() {
let expected = vec![OrderKind::Dir, OrderKind::Name];
let args = vec!["ex", "-i"];
let config = create_config(args);
assert_eq!(&expected, config.sort_order());
assert_eq!(false, config.sort_name());
let expected = vec![OrderKind::Dir, OrderKind::Name];
let args = vec!["ex", "-i", "-d0"];
let config = create_config(args);
assert_eq!(&expected, config.sort_order());
assert_eq!(false, config.sort_name());
let expected = vec![OrderKind::Dir, OrderKind::Name];
let args = vec!["ex", "-i", "-d1"];
let config = create_config(args);
assert_eq!(&expected, config.sort_order());
assert_eq!(false, config.sort_name());
let expected = vec![OrderKind::Dir, OrderKind::Name];
let args = vec!["ex", "-i", "-d2"];
let config = create_config(args);
assert_eq!(&expected, config.sort_order());
assert_eq!(false, config.sort_name());
let expected = vec![OrderKind::Dir, OrderKind::Name];
let args = vec!["ex", "-i", "-s"];
let config = create_config(args);
assert_eq!(&expected, config.sort_order());
assert_eq!(false, config.sort_name());
let expected = vec![OrderKind::Dir, OrderKind::Ext, OrderKind::Name];
let args = vec!["ex", "-i", "-oe"];
let config = create_config(args);
assert_eq!(&expected, config.sort_order());
assert_eq!(false, config.sort_name());
let expected = vec![OrderKind::Dir, OrderKind::Ext, OrderKind::Name];
let args = vec!["ex", "-i", "-oe", "-d0"];
let config = create_config(args);
assert_eq!(&expected, config.sort_order());
assert_eq!(false, config.sort_name());
let expected = vec![OrderKind::Dir, OrderKind::Ext, OrderKind::Name];
let args = vec!["ex", "-i", "-oe", "-d1"];
let config = create_config(args);
assert_eq!(&expected, config.sort_order());
assert_eq!(false, config.sort_name());
let expected = vec![OrderKind::Dir, OrderKind::Ext, OrderKind::Name];
let args = vec!["ex", "-i", "-oe", "-d2"];
let config = create_config(args);
assert_eq!(&expected, config.sort_order());
assert_eq!(false, config.sort_name());
let expected = vec![OrderKind::Dir, OrderKind::Ext, OrderKind::Name];
let args = vec!["ex", "-i", "-oe", "-s"];
let config = create_config(args);
assert_eq!(&expected, config.sort_order());
assert_eq!(false, config.sort_name());
}
#[test]
fn test_recent_is_handled() {
let args = vec!["ex"];
let config = create_config(args);
assert_eq!(RecentKind::None, config.filter_recent());
let args = vec!["ex", "-ry10"];
let config = create_config(args);
assert_eq!(RecentKind::Year(10), config.filter_recent());
let args = vec!["ex", "-rm6"];
let config = create_config(args);
assert_eq!(RecentKind::Month(6), config.filter_recent());
let args = vec!["ex", "-rw2"];
let config = create_config(args);
assert_eq!(RecentKind::Week(2), config.filter_recent());
let args = vec!["ex", "-rd"];
let config = create_config(args);
assert_eq!(RecentKind::Day(1), config.filter_recent());
let args = vec!["ex", "--recent=h"];
let config = create_config(args);
assert_eq!(RecentKind::Hour(1), config.filter_recent());
let args = vec!["ex", "--recent=H"];
let config = create_config(args);
assert_eq!(RecentKind::Hour(1), config.filter_recent());
let args = vec!["ex", "--recent=M5"];
let config = create_config(args);
assert_eq!(RecentKind::Min(5), config.filter_recent());
let args = vec!["ex", "--recent=S10"];
let config = create_config(args);
assert_eq!(RecentKind::Sec(10), config.filter_recent());
}
#[test]
fn test_none_is_subtracted_from_time() {
let now = create_time(2023, 7, 1, 0, 0, 0);
assert_eq!(None, RecentKind::None.subtract_from(&now, &Utc));
}
#[test]
fn test_second_is_subtracted_from_time() {
let now = create_time(2023, 7, 1, 0, 0, 0);
assert_eq!(Some(create_time(2023, 7, 1, 0, 0, 0)), RecentKind::Sec(0).subtract_from(&now, &Utc));
assert_eq!(Some(create_time(2023, 6, 30, 23, 59, 59)), RecentKind::Sec(1).subtract_from(&now, &Utc));
assert_eq!(Some(create_time(2023, 6, 30, 23, 59, 58)), RecentKind::Sec(2).subtract_from(&now, &Utc));
}
#[test]
fn test_minute_is_subtracted_from_time() {
let now = create_time(2023, 7, 1, 0, 0, 0);
assert_eq!(Some(create_time(2023, 7, 1, 0, 0, 0)), RecentKind::Min(0).subtract_from(&now, &Utc));
assert_eq!(Some(create_time(2023, 6, 30, 23, 59, 0)), RecentKind::Min(1).subtract_from(&now, &Utc));
assert_eq!(Some(create_time(2023, 6, 30, 23, 58, 0)), RecentKind::Min(2).subtract_from(&now, &Utc));
}
#[test]
fn test_hour_is_subtracted_from_time() {
let now = create_time(2023, 7, 1, 0, 0, 0);
assert_eq!(Some(create_time(2023, 7, 1, 0, 0, 0)), RecentKind::Hour(0).subtract_from(&now, &Utc));
assert_eq!(Some(create_time(2023, 6, 30, 23, 0, 0)), RecentKind::Hour(1).subtract_from(&now, &Utc));
assert_eq!(Some(create_time(2023, 6, 30, 22, 0, 0)), RecentKind::Hour(2).subtract_from(&now, &Utc));
}
#[test]
fn test_day_is_subtracted_from_time() {
let now = create_time(2023, 7, 1, 0, 0, 0);
assert_eq!(Some(create_time(2023, 7, 1, 0, 0, 0)), RecentKind::Day(0).subtract_from(&now, &Utc));
assert_eq!(Some(create_time(2023, 6, 30, 0, 0, 0)), RecentKind::Day(1).subtract_from(&now, &Utc));
assert_eq!(Some(create_time(2023, 6, 29, 0, 0, 0)), RecentKind::Day(2).subtract_from(&now, &Utc));
}
#[test]
fn test_week_is_subtracted_from_time() {
let now = create_time(2023, 7, 1, 0, 0, 0);
assert_eq!(Some(create_time(2023, 7, 1, 0, 0, 0)), RecentKind::Week(0).subtract_from(&now, &Utc));
assert_eq!(Some(create_time(2023, 6, 24, 0, 0, 0)), RecentKind::Week(1).subtract_from(&now, &Utc));
assert_eq!(Some(create_time(2023, 6, 17, 0, 0, 0)), RecentKind::Week(2).subtract_from(&now, &Utc));
}
#[test]
fn test_month_is_subtracted_from_time() {
let now = create_time(2023, 3, 31, 0, 0, 0);
assert_eq!(Some(create_time(2023, 3, 31, 0, 0, 0)), RecentKind::Month(0).subtract_from(&now, &Utc));
assert_eq!(Some(create_time(2023, 3, 1, 0, 0, 0)), RecentKind::Month(1).subtract_from(&now, &Utc));
assert_eq!(Some(create_time(2023, 1, 31, 0, 0, 0)), RecentKind::Month(2).subtract_from(&now, &Utc));
assert_eq!(Some(create_time(2022, 12, 31, 0, 0, 0)), RecentKind::Month(3).subtract_from(&now, &Utc));
assert_eq!(Some(create_time(2022, 12, 1, 0, 0, 0)), RecentKind::Month(4).subtract_from(&now, &Utc));
assert_eq!(Some(create_time(2022, 10, 31, 0, 0, 0)), RecentKind::Month(5).subtract_from(&now, &Utc));
}
#[test]
fn test_year_is_subtracted_from_time() {
let now = create_time(2024, 2, 29, 0, 0, 0);
assert_eq!(Some(create_time(2024, 2, 29, 0, 0, 0)), RecentKind::Year(0).subtract_from(&now, &Utc));
assert_eq!(Some(create_time(2023, 3, 1, 0, 0, 0)), RecentKind::Year(1).subtract_from(&now, &Utc));
assert_eq!(Some(create_time(2022, 3, 1, 0, 0, 0)), RecentKind::Year(2).subtract_from(&now, &Utc));
assert_eq!(Some(create_time(2021, 3, 1, 0, 0, 0)), RecentKind::Year(3).subtract_from(&now, &Utc));
assert_eq!(Some(create_time(2020, 2, 29, 0, 0, 0)), RecentKind::Year(4).subtract_from(&now, &Utc));
}
#[test]
fn test_type_is_handled() {
let args = vec!["ex"];
let config = create_config(args);
assert_eq!(None, config.filter_types());
let args = vec!["ex", "-tf"];
let config = create_config(args);
let expected = create_set(&[
FileKind::File(ExecKind::None),
FileKind::File(ExecKind::User),
FileKind::File(ExecKind::Other),
]);
assert_eq!(Some(&expected), config.filter_types());
let args = vec!["ex", "-te"];
let config = create_config(args);
let expected = create_set(&[
FileKind::File(ExecKind::User),
FileKind::File(ExecKind::Other),
]);
assert_eq!(Some(&expected), config.filter_types());
let args = vec!["ex", "-td"];
let config = create_config(args);
let expected = create_set(&[FileKind::Dir]);
assert_eq!(Some(&expected), config.filter_types());
let args = vec!["ex", "-tfd"];
let config = create_config(args);
let expected = create_set(&[
FileKind::File(ExecKind::None),
FileKind::File(ExecKind::User),
FileKind::File(ExecKind::Other),
FileKind::Dir,
]);
assert_eq!(Some(&expected), config.filter_types());
let args = vec!["ex", "--type=l"];
let config = create_config(args);
let expected = create_set(&[
FileKind::Link(false),
FileKind::Link(true),
]);
assert_eq!(Some(&expected), config.filter_types());
}
#[test]
fn test_git_is_handled() {
let args = vec!["ex"];
let config = create_config(args);
assert_eq!(None, config.filter_git());
let expected = GitFlags::default().with_everything(true);
let args = vec!["ex", "-gx"];
let config = create_config(args);
assert_eq!(Some(&expected), config.filter_git());
let expected = GitFlags::default().with_cached(true);
let args = vec!["ex", "-gc"];
let config = create_config(args);
assert_eq!(Some(&expected), config.filter_git());
let expected = GitFlags::default().with_added(true);
let args = vec!["ex", "-ga"];
let config = create_config(args);
assert_eq!(Some(&expected), config.filter_git());
let expected = GitFlags::default().with_modified(true);
let args = vec!["ex", "-gm"];
let config = create_config(args);
assert_eq!(Some(&expected), config.filter_git());
let expected = GitFlags::default().with_renamed(true);
let args = vec!["ex", "-gr"];
let config = create_config(args);
assert_eq!(Some(&expected), config.filter_git());
let expected = GitFlags::default().with_untracked(true);
let args = vec!["ex", "-gu"];
let config = create_config(args);
assert_eq!(Some(&expected), config.filter_git());
let expected = GitFlags::default().with_ignored(true);
let args = vec!["ex", "-gi"];
let config = create_config(args);
assert_eq!(Some(&expected), config.filter_git());
let expected = GitFlags::default().with_added(true).with_modified(true).with_renamed(true);
let args = vec!["ex", "--git=amr"];
let config = create_config(args);
assert_eq!(Some(&expected), config.filter_git());
}
#[test]
fn test_precise_is_handled() {
let args = vec!["ex"];
let config = create_config(args);
assert_eq!(false, config.show_precise());
let args = vec!["ex", "-p"];
let config = create_config(args);
assert_eq!(true, config.show_precise());
let args = vec!["ex", "--precise"];
let config = create_config(args);
assert_eq!(true, config.show_precise());
}
#[test]
fn test_utc_is_handled() {
let args = vec!["ex"];
let config = create_config(args);
assert_eq!(false, config.show_utc());
let args = vec!["ex", "-u"];
let config = create_config(args);
assert_eq!(true, config.show_utc());
let args = vec!["ex", "--utc"];
let config = create_config(args);
assert_eq!(true, config.show_utc());
}
#[test]
fn test_total_is_handled() {
let args = vec!["ex"];
let config = create_config(args);
assert_eq!(false, config.show_total());
let args = vec!["ex", "--total"];
let config = create_config(args);
assert_eq!(true, config.show_total());
}
#[test]
#[cfg(unix)]
fn test_owner_is_handled() {
let args = vec!["ex"];
let config = create_config(args);
assert_eq!(false, config.show_owner());
let args = vec!["ex", "--owner"];
let config = create_config(args);
assert_eq!(true, config.show_owner());
}
#[test]
fn test_data_is_handled() {
let args = vec!["ex"];
let config = create_config(args);
assert_eq!(false, config.show_sig());
let args = vec!["ex", "--sig"];
let config = create_config(args);
assert_eq!(true, config.show_sig());
}
#[test]
fn test_only_path_is_handled_with_terminal() {
let args = vec!["ex"];
let config = create_config_with_piped(args, false);
assert_eq!(false, config.only_path()); assert_eq!(false, config.escape_path()); assert_eq!(false, config.null_path());
let args = vec!["ex", "-x"];
let config = create_config_with_piped(args, false);
assert_eq!(true, config.only_path());
assert_eq!(false, config.escape_path());
assert_eq!(false, config.null_path());
let args = vec!["ex", "-x", "-x"];
let config = create_config_with_piped(args, false);
assert_eq!(false, config.only_path());
assert_eq!(false, config.escape_path());
assert_eq!(false, config.null_path());
let args = vec!["ex", "-xx"];
let config = create_config_with_piped(args, false);
assert_eq!(false, config.only_path());
assert_eq!(false, config.escape_path());
assert_eq!(false, config.null_path());
let args = vec!["ex", "--only-path"];
let config = create_config_with_piped(args, false);
assert_eq!(true, config.only_path());
assert_eq!(false, config.escape_path());
assert_eq!(false, config.null_path());
}
#[test]
fn test_only_path_is_handled_with_piped() {
let args = vec!["ex"];
let config = create_config_with_piped(args, true);
assert_eq!(true, config.only_path()); assert_eq!(true, config.escape_path()); assert_eq!(false, config.null_path());
let args = vec!["ex", "-x"];
let config = create_config_with_piped(args, true);
assert_eq!(true, config.only_path());
assert_eq!(false, config.escape_path());
assert_eq!(false, config.null_path());
let args = vec!["ex", "-x", "-x"];
let config = create_config_with_piped(args, true);
assert_eq!(false, config.only_path());
assert_eq!(false, config.escape_path());
assert_eq!(false, config.null_path());
let args = vec!["ex", "-xx"];
let config = create_config_with_piped(args, true);
assert_eq!(false, config.only_path());
assert_eq!(false, config.escape_path());
assert_eq!(false, config.null_path());
let args = vec!["ex", "--only-path"];
let config = create_config_with_piped(args, true);
assert_eq!(true, config.only_path());
assert_eq!(false, config.escape_path());
assert_eq!(false, config.null_path());
}
#[test]
#[cfg(debug_assertions)]
fn test_only_path_is_handled_with_override() {
let args = vec!["ex", "--terminal"];
let config = create_config_with_piped(args, true);
assert_eq!(false, config.only_path()); assert_eq!(false, config.escape_path()); assert_eq!(false, config.null_path());
let args = vec!["ex", "--terminal", "-x"];
let config = create_config_with_piped(args, true);
assert_eq!(true, config.only_path());
assert_eq!(false, config.escape_path());
assert_eq!(false, config.null_path());
let args = vec!["ex", "--terminal", "-x", "-x"];
let config = create_config_with_piped(args, true);
assert_eq!(false, config.only_path());
assert_eq!(false, config.escape_path());
assert_eq!(false, config.null_path());
let args = vec!["ex", "--terminal", "-xx"];
let config = create_config_with_piped(args, true);
assert_eq!(false, config.only_path());
assert_eq!(false, config.escape_path());
assert_eq!(false, config.null_path());
let args = vec!["ex", "--terminal", "--only-path"];
let config = create_config_with_piped(args, true);
assert_eq!(true, config.only_path());
assert_eq!(false, config.escape_path());
assert_eq!(false, config.null_path());
}
#[test]
fn test_null_path_is_handled() {
let args = vec!["ex"];
let config = create_config_with_piped(args, false);
assert_eq!(false, config.only_path());
assert_eq!(false, config.escape_path());
assert_eq!(false, config.null_path());
let args = vec!["ex", "-z"]; let config = create_config_with_piped(args, false);
assert_eq!(false, config.only_path());
assert_eq!(false, config.escape_path());
assert_eq!(false, config.null_path());
let args = vec!["ex", "--null-path"];
let config = create_config_with_piped(args, false);
assert_eq!(true, config.only_path());
assert_eq!(false, config.escape_path());
assert_eq!(true, config.null_path());
}
#[test]
fn test_abs_path_is_handled() {
let args = vec!["ex"];
let config = create_config(args);
assert_eq!(false, config.abs_path());
let args = vec!["ex", "-q"];
let config = create_config(args);
assert_eq!(true, config.abs_path());
let args = vec!["ex", "--abs-path"];
let config = create_config(args);
assert_eq!(true, config.abs_path());
}
#[test]
#[cfg(windows)]
fn test_win_path_is_handled() {
let args = vec!["ex"];
let config = create_config(args);
assert_eq!(false, config.win_path());
let args = vec!["ex", "-w"];
let config = create_config(args);
assert_eq!(true, config.win_path());
let args = vec!["ex", "--win-path"];
let config = create_config(args);
assert_eq!(true, config.win_path());
}
#[test]
#[cfg(windows)]
fn test_win_ver_is_handled() {
let args = vec!["ex"];
let config = create_config(args);
assert_eq!(false, config.win_ver());
let args = vec!["ex", "-v"];
let config = create_config(args);
assert_eq!(true, config.win_ver());
let args = vec!["ex", "--win-ver"];
let config = create_config(args);
assert_eq!(true, config.win_ver());
}
#[test]
fn test_patterns_are_handled() {
let expected = vec!["."];
let args = vec!["ex"];
let config = create_config(args);
assert_eq!(&expected, config.patterns());
let expected = vec!["file1"];
let args = vec!["ex", "file1"];
let config = create_config(args);
assert_eq!(&expected, config.patterns());
let expected = vec!["file1", "file2"];
let args = vec!["ex", "file1", "file2"];
let config = create_config(args);
assert_eq!(&expected, config.patterns());
}
#[test]
#[should_panic(expected = "Invalid depth option: foo")]
fn test_unexpected_depth_causes_error() {
let args = vec!["ex", "-dfoo"];
create_config(args);
}
#[test]
#[should_panic(expected = "Invalid order option: foo")]
fn test_unexpected_order_causes_error() {
let args = vec!["ex", "-ofoo"];
create_config(args);
}
#[test]
#[should_panic(expected = "Invalid recent option: foo")]
fn test_unexpected_recent_causes_error() {
let args = vec!["ex", "-rfoo"];
create_config(args);
}
#[test]
#[should_panic(expected = "Invalid type option: z")]
fn test_unexpected_type_causes_error() {
let args = vec!["ex", "-tfzd"];
create_config(args);
}
#[test]
#[should_panic(expected = "Invalid git option: z")]
fn test_unexpected_git_causes_error() {
let args = vec!["ex", "-gazm"];
create_config(args);
}
fn create_config(args: Vec<&str>) -> Config {
create_config_with_piped(args, false)
}
fn create_config_with_piped(args: Vec<&str>, piped: bool) -> Config {
let args = args.into_iter().map(String::from).collect();
Config::new(args, piped, DateTime::default).unwrap()
}
fn create_time(year: i32, month: u32, day: u32, hour: u32, minute: u32, second: u32) -> DateTime<Utc> {
let date = NaiveDate::from_ymd_opt(year, month, day).unwrap();
let time = NaiveTime::from_hms_opt(hour, minute, second).unwrap();
let time = DateTime::from_naive_utc_and_offset(NaiveDateTime::new(date, time), Utc);
time
}
fn create_set<T: Clone + Eq + Hash>(values: &[T]) -> HashSet<T> {
values.iter().map(T::clone).collect()
}
impl Config {
pub fn with_curr_time(
mut self,
year: i32,
month: u32,
day: u32,
hour: u32,
min: u32,
sec: u32,
) -> Self {
self.curr_time = Utc.with_ymd_and_hms(year, month, day, hour, min, sec).unwrap();
self
}
pub fn with_recurse_all(mut self, recurse_all: bool) -> Self {
self.cli.recurse_all = recurse_all;
self
}
pub fn with_min_depth(mut self, min_depth: usize) -> Self {
self.cli.recurse_depth.get_or_insert_default().min_depth = Some(min_depth);
self
}
pub fn with_max_depth(mut self, max_depth: usize) -> Self {
self.cli.recurse_depth.get_or_insert_default().max_depth = Some(max_depth);
self
}
pub fn with_show_indent(mut self, show_indent: bool) -> Self {
self.cli.show_indent = show_indent;
self
}
pub fn with_zip_expand(mut self, zip_expand: bool) -> Self {
self.cli.zip_expand = zip_expand;
self
}
pub fn with_case_sensitive(mut self, case_sensitive: bool) -> Self {
if case_sensitive {
self.cli.case_sensitive = true;
self.cli.case_insensitive = false;
} else {
self.cli.case_sensitive = false;
self.cli.case_insensitive = true;
}
self
}
pub fn with_sort_order(mut self, sort_order: Vec<OrderKind>) -> Self {
self.sort_order = sort_order;
self
}
pub fn with_sort_name(mut self, sort_name: bool) -> Self {
self.sort_name = sort_name;
self
}
pub fn with_filter_recent(mut self, filter_recent: RecentKind) -> Self {
self.cli.filter_recent = Some(filter_recent);
self
}
pub fn with_filter_types(mut self, filter_types: Vec<FileKind>) -> Self {
let filter_types = FileSet { inner: filter_types.into_iter().collect() };
self.cli.filter_types = Some(filter_types);
self
}
pub fn with_filter_git(mut self, filter_git: GitFlags) -> Self {
self.cli.filter_git = Some(filter_git);
self
}
pub fn with_show_precise(mut self, show_precise: bool) -> Self {
self.cli.show_precise = show_precise;
self
}
pub fn with_show_utc(mut self, show_utc: bool) -> Self {
self.cli.show_utc = show_utc;
self
}
pub fn with_show_total(mut self, show_total: bool) -> Self {
self.cli.show_total = show_total;
self
}
#[cfg(unix)]
pub fn with_show_owner(mut self, show_owner: bool) -> Self {
self.cli.show_owner = show_owner;
self
}
pub fn with_show_sig(mut self, show_sig: bool) -> Self {
self.cli.show_sig = show_sig;
self
}
pub fn with_only_path(mut self, only_path: bool) -> Self {
self.cli.only_path = if only_path { 1 } else { 2 };
self
}
pub fn with_escape_path(mut self) -> Self {
self.cli.only_path = 0;
self.cli.null_path = false;
self.piped = true;
self
}
pub fn with_abs_path(mut self, abs_path: bool) -> Self {
self.cli.abs_path = abs_path;
self
}
#[cfg(windows)]
pub fn with_win_ver(mut self, win_ver: bool) -> Self {
self.cli.win_ver = win_ver;
self
}
pub fn with_patterns(mut self, patterns: Vec<&str>) -> Self {
self.cli.patterns = patterns.into_iter().map(String::from).collect();
self
}
}
}