use crate::cli::cli::Cli;
use crate::cli::file::FileKind;
use crate::cli::hidden::HiddenKind;
use crate::cli::order::OrderKind;
use crate::cli::recent::{PeriodKind, 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(Debug, 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<PeriodKind> {
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_crc(&self) -> bool {
self.cli.show_crc
}
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) -> RecentKind<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::{PeriodKind, RecentKind};
use crate::config::{Config, OrderKind};
use crate::error::MyResult;
use crate::git::flags::GitFlags;
use crate::util::matcher::tests::*;
use crate::util::time::tests::create_time;
use chrono::{DateTime, Utc};
use googletest::prelude::*;
#[gtest]
fn test_depth_is_handled() -> MyResult<()> {
let args = vec!["ex"];
let config = create_config(args)?;
expect_that!(config.min_depth(), some(eq(1)));
expect_that!(config.max_depth(), some(eq(1)));
let args = vec!["ex", "-d4"];
let config = create_config(args)?;
expect_that!(config.min_depth(), some(eq(1)));
expect_that!(config.max_depth(), some(eq(5)));
let args = vec!["ex", "-d-4"];
let config = create_config(args)?;
expect_that!(config.min_depth(), some(eq(1)));
expect_that!(config.max_depth(), some(eq(5)));
let args = vec!["ex", "-d2-4"];
let config = create_config(args)?;
expect_that!(config.min_depth(), some(eq(3)));
expect_that!(config.max_depth(), some(eq(5)));
let args = vec!["ex", "-d2-"];
let config = create_config(args)?;
expect_that!(config.min_depth(), some(eq(3)));
expect_that!(config.max_depth(), none());
let args = vec!["ex", "-s"];
let config = create_config(args)?;
expect_that!(config.min_depth(), some(eq(1)));
expect_that!(config.max_depth(), none());
let args = vec!["ex", "-s", "-d4"];
let config = create_config(args)?;
expect_that!(config.min_depth(), some(eq(1)));
expect_that!(config.max_depth(), none());
let args = vec!["ex", "--recurse"];
let config = create_config(args)?;
expect_that!(config.min_depth(), some(eq(1)));
expect_that!(config.max_depth(), none());
let args = vec!["ex", "--depth=4"];
let config = create_config(args)?;
expect_that!(config.min_depth(), some(eq(1)));
expect_that!(config.max_depth(), some(eq(5)));
Ok(())
}
#[gtest]
fn test_indent_is_handled() -> MyResult<()> {
let args = vec!["ex"];
let config = create_config(args)?;
expect_false!(config.show_indent());
let args = vec!["ex", "-i"];
let config = create_config(args)?;
expect_true!(config.show_indent());
let args = vec!["ex", "--indent"];
let config = create_config(args)?;
expect_true!(config.show_indent());
Ok(())
}
#[gtest]
fn test_all_files_is_handled() -> MyResult<()> {
let args = vec!["ex"];
let config = create_config(args)?;
expect_eq!(config.show_hidden(), HiddenKind::None);
let args = vec!["ex", "-a"];
let config = create_config(args)?;
expect_eq!(config.show_hidden(), HiddenKind::Files);
let args = vec!["ex", "-aa"];
let config = create_config(args)?;
expect_eq!(config.show_hidden(), HiddenKind::Recurse);
let args = vec!["ex", "-a", "-a"];
let config = create_config(args)?;
expect_eq!(config.show_hidden(), HiddenKind::Recurse);
let args = vec!["ex", "--all-files"];
let config = create_config(args)?;
expect_eq!(config.show_hidden(), HiddenKind::Files);
Ok(())
}
#[gtest]
fn test_zip_is_handled() -> MyResult<()> {
let args = vec!["ex"];
let config = create_config(args)?;
expect_false!(config.zip_expand());
let args = vec!["ex", "-z"];
let config = create_config(args)?;
expect_true!(config.zip_expand());
let args = vec!["ex", "--zip"];
let config = create_config(args)?;
expect_true!(config.zip_expand());
Ok(())
}
#[gtest]
fn test_password_is_handled() -> MyResult<()> {
let args = vec!["ex"];
let config = create_config(args)?;
expect_that!(config.zip_password(), none());
let args = vec!["ex", "--password", "secret"];
let config = create_config(args)?;
expect_that!(config.zip_password(), some(eq("secret")));
Ok(())
}
#[gtest]
fn test_case_is_handled() -> MyResult<()> {
let args = vec!["ex"];
let config = create_config(args)?;
expect_that!(config.case_sensitive(), none());
let args = vec!["ex", "--case"];
let config = create_config(args)?;
expect_that!(config.case_sensitive(), some(eq(true)));
let args = vec!["ex", "--case", "--no-case"];
let config = create_config(args)?;
expect_that!(config.case_sensitive(), some(eq(false)));
let args = vec!["ex", "--no-case"];
let config = create_config(args)?;
expect_that!(config.case_sensitive(), some(eq(false)));
let args = vec!["ex", "--no-case", "--case"];
let config = create_config(args)?;
expect_that!(config.case_sensitive(), some(eq(true)));
Ok(())
}
#[gtest]
fn test_order_is_handled() -> MyResult<()> {
let args = vec!["ex"];
let config = create_config(args)?;
expect_that!(config.sort_order(), elements_are![
&OrderKind::Group,
&OrderKind::Dir,
&OrderKind::Name,
]);
expect_false!(config.sort_name());
let args = vec!["ex", "-od"];
let config = create_config(args)?;
expect_that!(config.sort_order(), elements_are![
&OrderKind::Dir,
&OrderKind::Name,
]);
expect_false!(config.sort_name());
let args = vec!["ex", "-on"];
let config = create_config(args)?;
expect_that!(config.sort_order(), elements_are![
&OrderKind::Name,
&OrderKind::Dir,
]);
expect_true!(config.sort_name());
let args = vec!["ex", "-oe"];
let config = create_config(args)?;
expect_that!(config.sort_order(), elements_are![
&OrderKind::Ext,
&OrderKind::Dir,
&OrderKind::Name,
]);
expect_false!(config.sort_name());
let args = vec!["ex", "-os"];
let config = create_config(args)?;
expect_that!(config.sort_order(), elements_are![
&OrderKind::Size(DirKind::Asc),
&OrderKind::Dir,
&OrderKind::Name,
]);
expect_false!(config.sort_name());
let args = vec!["ex", "-os+"];
let config = create_config(args)?;
expect_that!(config.sort_order(), elements_are![
&OrderKind::Size(DirKind::Asc),
&OrderKind::Dir,
&OrderKind::Name,
]);
expect_false!(config.sort_name());
let args = vec!["ex", "-os-"];
let config = create_config(args)?;
expect_that!(config.sort_order(), elements_are![
&OrderKind::Size(DirKind::Desc),
&OrderKind::Dir,
&OrderKind::Name,
]);
expect_false!(config.sort_name());
let args = vec!["ex", "-ot"];
let config = create_config(args)?;
expect_that!(config.sort_order(), elements_are![
&OrderKind::Time(DirKind::Asc),
&OrderKind::Dir,
&OrderKind::Name,
]);
expect_false!(config.sort_name());
let args = vec!["ex", "-ot+"];
let config = create_config(args)?;
expect_that!(config.sort_order(), elements_are![
&OrderKind::Time(DirKind::Asc),
&OrderKind::Dir,
&OrderKind::Name,
]);
expect_false!(config.sort_name());
let args = vec!["ex", "-ot-"];
let config = create_config(args)?;
expect_that!(config.sort_order(), elements_are![
&OrderKind::Time(DirKind::Desc),
&OrderKind::Dir,
&OrderKind::Name,
]);
expect_false!(config.sort_name());
let args = vec!["ex", "--order=dest"];
let config = create_config(args)?;
expect_that!(config.sort_order(), elements_are![
&OrderKind::Dir,
&OrderKind::Ext,
&OrderKind::Size(DirKind::Asc),
&OrderKind::Time(DirKind::Asc),
&OrderKind::Name,
]);
expect_false!(config.sort_name());
let args = vec!["ex", "--order=est"];
let config = create_config(args)?;
expect_that!(config.sort_order(), elements_are![
&OrderKind::Ext,
&OrderKind::Size(DirKind::Asc),
&OrderKind::Time(DirKind::Asc),
&OrderKind::Dir,
&OrderKind::Name,
]);
expect_false!(config.sort_name());
let args = vec!["ex", "--order=e+s+t+"];
let config = create_config(args)?;
expect_that!(config.sort_order(), elements_are![
&OrderKind::Ext,
&OrderKind::Size(DirKind::Asc),
&OrderKind::Time(DirKind::Asc),
&OrderKind::Dir,
&OrderKind::Name,
]);
expect_false!(config.sort_name());
let args = vec!["ex", "--order=e-s-t-"];
let config = create_config(args)?;
expect_that!(config.sort_order(), elements_are![
&OrderKind::Ext,
&OrderKind::Size(DirKind::Desc),
&OrderKind::Time(DirKind::Desc),
&OrderKind::Dir,
&OrderKind::Name,
]);
expect_false!(config.sort_name());
Ok(())
}
#[gtest]
fn test_order_defaults_to_group_with_no_recursion() -> MyResult<()> {
let args = vec!["ex"];
let config = create_config(args)?;
expect_that!(config.sort_order(), elements_are![
&OrderKind::Group,
&OrderKind::Dir,
&OrderKind::Name,
]);
expect_false!(config.sort_name());
let args = vec!["ex", "-d0"];
let config = create_config(args)?;
expect_that!(config.sort_order(), elements_are![
&OrderKind::Group,
&OrderKind::Dir,
&OrderKind::Name,
]);
expect_false!(config.sort_name());
let args = vec!["ex", "-d1"];
let config = create_config(args)?;
expect_that!(config.sort_order(), elements_are![
&OrderKind::Dir,
&OrderKind::Name,
]);
expect_false!(config.sort_name());
let args = vec!["ex", "-d2"];
let config = create_config(args)?;
expect_that!(config.sort_order(), elements_are![
&OrderKind::Dir,
&OrderKind::Name,
]);
expect_false!(config.sort_name());
let args = vec!["ex", "-s"];
let config = create_config(args)?;
expect_that!(config.sort_order(), elements_are![
&OrderKind::Dir,
&OrderKind::Name,
]);
expect_false!(config.sort_name());
let args = vec!["ex", "-oe"];
let config = create_config(args)?;
expect_that!(config.sort_order(), elements_are![
&OrderKind::Ext,
&OrderKind::Dir,
&OrderKind::Name,
]);
expect_false!(config.sort_name());
let args = vec!["ex", "-oe", "-d0"];
let config = create_config(args)?;
expect_that!(config.sort_order(), elements_are![
&OrderKind::Ext,
&OrderKind::Dir,
&OrderKind::Name,
]);
expect_false!(config.sort_name());
let args = vec!["ex", "-oe", "-d1"];
let config = create_config(args)?;
expect_that!(config.sort_order(), elements_are![
&OrderKind::Ext,
&OrderKind::Dir,
&OrderKind::Name,
]);
expect_false!(config.sort_name());
let args = vec!["ex", "-oe", "-d2"];
let config = create_config(args)?;
expect_that!(config.sort_order(), elements_are![
&OrderKind::Ext,
&OrderKind::Dir,
&OrderKind::Name,
]);
expect_false!(config.sort_name());
let args = vec!["ex", "-oe", "-s"];
let config = create_config(args)?;
expect_that!(config.sort_order(), elements_are![
&OrderKind::Ext,
&OrderKind::Dir,
&OrderKind::Name,
]);
expect_false!(config.sort_name());
Ok(())
}
#[gtest]
fn test_order_defaults_to_directory_with_indent() -> MyResult<()> {
let args = vec!["ex", "-i"];
let config = create_config(args)?;
expect_that!(config.sort_order(), elements_are![
&OrderKind::Dir,
&OrderKind::Name,
]);
expect_false!(config.sort_name());
let args = vec!["ex", "-i", "-d0"];
let config = create_config(args)?;
expect_that!(config.sort_order(), elements_are![
&OrderKind::Dir,
&OrderKind::Name,
]);
expect_false!(config.sort_name());
let args = vec!["ex", "-i", "-d1"];
let config = create_config(args)?;
expect_that!(config.sort_order(), elements_are![
&OrderKind::Dir,
&OrderKind::Name,
]);
expect_false!(config.sort_name());
let args = vec!["ex", "-i", "-d2"];
let config = create_config(args)?;
expect_that!(config.sort_order(), elements_are![
&OrderKind::Dir,
&OrderKind::Name,
]);
expect_false!(config.sort_name());
let args = vec!["ex", "-i", "-s"];
let config = create_config(args)?;
expect_that!(config.sort_order(), elements_are![
&OrderKind::Dir,
&OrderKind::Name,
]);
expect_false!(config.sort_name());
let args = vec!["ex", "-i", "-oe"];
let config = create_config(args)?;
expect_that!(config.sort_order(), elements_are![
&OrderKind::Dir,
&OrderKind::Ext,
&OrderKind::Name,
]);
expect_false!(config.sort_name());
let args = vec!["ex", "-i", "-oe", "-d0"];
let config = create_config(args)?;
expect_that!(config.sort_order(), elements_are![
&OrderKind::Dir,
&OrderKind::Ext,
&OrderKind::Name,
]);
expect_false!(config.sort_name());
let args = vec!["ex", "-i", "-oe", "-d1"];
let config = create_config(args)?;
expect_that!(config.sort_order(), elements_are![
&OrderKind::Dir,
&OrderKind::Ext,
&OrderKind::Name,
]);
expect_false!(config.sort_name());
let args = vec!["ex", "-i", "-oe", "-d2"];
let config = create_config(args)?;
expect_that!(config.sort_order(), elements_are![
&OrderKind::Dir,
&OrderKind::Ext,
&OrderKind::Name,
]);
expect_false!(config.sort_name());
let args = vec!["ex", "-i", "-oe", "-s"];
let config = create_config(args)?;
expect_that!(config.sort_order(), elements_are![
&OrderKind::Dir,
&OrderKind::Ext,
&OrderKind::Name,
]);
expect_false!(config.sort_name());
Ok(())
}
#[gtest]
fn test_before_recent_is_handled() -> MyResult<()> {
let args = vec!["ex"];
let config = create_config(args)?;
expect_eq!(config.filter_recent(), RecentKind::None);
let args = vec!["ex", "-ry10-"];
let config = create_config(args)?;
expect_eq!(config.filter_recent(), RecentKind::Before(PeriodKind::Year(10)));
let args = vec!["ex", "-rm6-"];
let config = create_config(args)?;
expect_eq!(config.filter_recent(), RecentKind::Before(PeriodKind::Month(6)));
let args = vec!["ex", "-rw2-"];
let config = create_config(args)?;
expect_eq!(config.filter_recent(), RecentKind::Before(PeriodKind::Week(2)));
let args = vec!["ex", "-rd-"];
let config = create_config(args)?;
expect_eq!(config.filter_recent(), RecentKind::Before(PeriodKind::Day(1)));
let args = vec!["ex", "--recent=h-"];
let config = create_config(args)?;
expect_eq!(config.filter_recent(), RecentKind::Before(PeriodKind::Hour(1)));
let args = vec!["ex", "--recent=H-"];
let config = create_config(args)?;
expect_eq!(config.filter_recent(), RecentKind::Before(PeriodKind::Hour(1)));
let args = vec!["ex", "--recent=M5-"];
let config = create_config(args)?;
expect_eq!(config.filter_recent(), RecentKind::Before(PeriodKind::Min(5)));
let args = vec!["ex", "--recent=S10-"];
let config = create_config(args)?;
expect_eq!(config.filter_recent(), RecentKind::Before(PeriodKind::Sec(10)));
Ok(())
}
#[gtest]
fn test_after_recent_is_handled() -> MyResult<()> {
let args = vec!["ex"];
let config = create_config(args)?;
expect_eq!(config.filter_recent(), RecentKind::None);
let args = vec!["ex", "-ry10"];
let config = create_config(args)?;
expect_eq!(config.filter_recent(), RecentKind::After(PeriodKind::Year(10)));
let args = vec!["ex", "-rm6"];
let config = create_config(args)?;
expect_eq!(config.filter_recent(), RecentKind::After(PeriodKind::Month(6)));
let args = vec!["ex", "-rw2+"];
let config = create_config(args)?;
expect_eq!(config.filter_recent(), RecentKind::After(PeriodKind::Week(2)));
let args = vec!["ex", "-rd+"];
let config = create_config(args)?;
expect_eq!(config.filter_recent(), RecentKind::After(PeriodKind::Day(1)));
let args = vec!["ex", "--recent=h"];
let config = create_config(args)?;
expect_eq!(config.filter_recent(), RecentKind::After(PeriodKind::Hour(1)));
let args = vec!["ex", "--recent=H"];
let config = create_config(args)?;
expect_eq!(config.filter_recent(), RecentKind::After(PeriodKind::Hour(1)));
let args = vec!["ex", "--recent=M5"];
let config = create_config(args)?;
expect_eq!(config.filter_recent(), RecentKind::After(PeriodKind::Min(5)));
let args = vec!["ex", "--recent=S10"];
let config = create_config(args)?;
expect_eq!(config.filter_recent(), RecentKind::After(PeriodKind::Sec(10)));
Ok(())
}
#[gtest]
fn test_none_is_subtracted_from_time() {
let now = create_time(2023, 7, 1, 0, 0, 0).unwrap();
expect_that!(RecentKind::None.subtract_from(&now, &Utc).to_option(), none());
}
#[gtest]
fn test_second_is_subtracted_from_time() {
let now = create_time(2023, 7, 1, 0, 0, 0).unwrap();
expect_that!(RecentKind::After(PeriodKind::Sec(0)).subtract_from(&now, &Utc).to_option(), some(time_eq(2023, 7, 1, 0, 0, 0)));
expect_that!(RecentKind::After(PeriodKind::Sec(1)).subtract_from(&now, &Utc).to_option(), some(time_eq(2023, 6, 30, 23, 59, 59)));
expect_that!(RecentKind::After(PeriodKind::Sec(2)).subtract_from(&now, &Utc).to_option(), some(time_eq(2023, 6, 30, 23, 59, 58)));
}
#[gtest]
fn test_minute_is_subtracted_from_time() {
let now = create_time(2023, 7, 1, 0, 0, 0).unwrap();
expect_that!(RecentKind::After(PeriodKind::Min(0)).subtract_from(&now, &Utc).to_option(), some(time_eq(2023, 7, 1, 0, 0, 0)));
expect_that!(RecentKind::After(PeriodKind::Min(1)).subtract_from(&now, &Utc).to_option(), some(time_eq(2023, 6, 30, 23, 59, 0)));
expect_that!(RecentKind::After(PeriodKind::Min(2)).subtract_from(&now, &Utc).to_option(), some(time_eq(2023, 6, 30, 23, 58, 0)));
}
#[gtest]
fn test_hour_is_subtracted_from_time() {
let now = create_time(2023, 7, 1, 0, 0, 0).unwrap();
expect_that!(RecentKind::After(PeriodKind::Hour(0)).subtract_from(&now, &Utc).to_option(), some(time_eq(2023, 7, 1, 0, 0, 0)));
expect_that!(RecentKind::After(PeriodKind::Hour(1)).subtract_from(&now, &Utc).to_option(), some(time_eq(2023, 6, 30, 23, 0, 0)));
expect_that!(RecentKind::After(PeriodKind::Hour(2)).subtract_from(&now, &Utc).to_option(), some(time_eq(2023, 6, 30, 22, 0, 0)));
}
#[gtest]
fn test_day_is_subtracted_from_time() {
let now = create_time(2023, 7, 1, 0, 0, 0).unwrap();
expect_that!(RecentKind::After(PeriodKind::Day(0)).subtract_from(&now, &Utc).to_option(), some(time_eq(2023, 7, 1, 0, 0, 0)));
expect_that!(RecentKind::After(PeriodKind::Day(1)).subtract_from(&now, &Utc).to_option(), some(time_eq(2023, 6, 30, 0, 0, 0)));
expect_that!(RecentKind::After(PeriodKind::Day(2)).subtract_from(&now, &Utc).to_option(), some(time_eq(2023, 6, 29, 0, 0, 0)));
}
#[gtest]
fn test_week_is_subtracted_from_time() {
let now = create_time(2023, 7, 1, 0, 0, 0).unwrap();
expect_that!(RecentKind::After(PeriodKind::Week(0)).subtract_from(&now, &Utc).to_option(), some(time_eq(2023, 7, 1, 0, 0, 0)));
expect_that!(RecentKind::After(PeriodKind::Week(1)).subtract_from(&now, &Utc).to_option(), some(time_eq(2023, 6, 24, 0, 0, 0)));
expect_that!(RecentKind::After(PeriodKind::Week(2)).subtract_from(&now, &Utc).to_option(), some(time_eq(2023, 6, 17, 0, 0, 0)));
}
#[gtest]
fn test_month_is_subtracted_from_time() {
let now = create_time(2023, 3, 31, 0, 0, 0).unwrap();
expect_that!(RecentKind::After(PeriodKind::Month(0)).subtract_from(&now, &Utc).to_option(), some(time_eq(2023, 3, 31, 0, 0, 0)));
expect_that!(RecentKind::After(PeriodKind::Month(1)).subtract_from(&now, &Utc).to_option(), some(time_eq(2023, 3, 1, 0, 0, 0)));
expect_that!(RecentKind::After(PeriodKind::Month(2)).subtract_from(&now, &Utc).to_option(), some(time_eq(2023, 1, 31, 0, 0, 0)));
expect_that!(RecentKind::After(PeriodKind::Month(3)).subtract_from(&now, &Utc).to_option(), some(time_eq(2022, 12, 31, 0, 0, 0)));
expect_that!(RecentKind::After(PeriodKind::Month(4)).subtract_from(&now, &Utc).to_option(), some(time_eq(2022, 12, 1, 0, 0, 0)));
expect_that!(RecentKind::After(PeriodKind::Month(5)).subtract_from(&now, &Utc).to_option(), some(time_eq(2022, 10, 31, 0, 0, 0)));
}
#[gtest]
fn test_year_is_subtracted_from_time() {
let now = create_time(2024, 2, 29, 0, 0, 0).unwrap();
expect_that!(RecentKind::After(PeriodKind::Year(0)).subtract_from(&now, &Utc).to_option(), some(time_eq(2024, 2, 29, 0, 0, 0)));
expect_that!(RecentKind::After(PeriodKind::Year(1)).subtract_from(&now, &Utc).to_option(), some(time_eq(2023, 3, 1, 0, 0, 0)));
expect_that!(RecentKind::After(PeriodKind::Year(2)).subtract_from(&now, &Utc).to_option(), some(time_eq(2022, 3, 1, 0, 0, 0)));
expect_that!(RecentKind::After(PeriodKind::Year(3)).subtract_from(&now, &Utc).to_option(), some(time_eq(2021, 3, 1, 0, 0, 0)));
expect_that!(RecentKind::After(PeriodKind::Year(4)).subtract_from(&now, &Utc).to_option(), some(time_eq(2020, 2, 29, 0, 0, 0)));
}
#[gtest]
fn test_type_is_handled() -> MyResult<()> {
let args = vec!["ex"];
let config = create_config(args)?;
expect_that!(config.filter_types(), none());
let args = vec!["ex", "-tf"];
let config = create_config(args)?;
expect_that!(config.filter_types(), some(unordered_elements_are![
&FileKind::File(ExecKind::None),
&FileKind::File(ExecKind::User),
&FileKind::File(ExecKind::Other),
]));
let args = vec!["ex", "-te"];
let config = create_config(args)?;
expect_that!(config.filter_types(), some(unordered_elements_are![
&FileKind::File(ExecKind::User),
&FileKind::File(ExecKind::Other),
]));
let args = vec!["ex", "-td"];
let config = create_config(args)?;
expect_that!(config.filter_types(), some(unordered_elements_are![
&FileKind::Dir,
]));
let args = vec!["ex", "-tfd"];
let config = create_config(args)?;
expect_that!(config.filter_types(), some(unordered_elements_are![
&FileKind::File(ExecKind::None),
&FileKind::File(ExecKind::User),
&FileKind::File(ExecKind::Other),
&FileKind::Dir,
]));
let args = vec!["ex", "--type=l"];
let config = create_config(args)?;
expect_that!(config.filter_types(), some(unordered_elements_are![
&FileKind::Link(false),
&FileKind::Link(true),
]));
let args = vec!["ex", "--type=bcps"];
let config = create_config(args)?;
expect_that!(config.filter_types(), some(unordered_elements_are![
&FileKind::Block,
&FileKind::Char,
&FileKind::Pipe,
&FileKind::Socket,
]));
Ok(())
}
#[gtest]
fn test_git_is_handled() -> MyResult<()> {
let args = vec!["ex"];
let config = create_config(args)?;
expect_that!(config.filter_git(), none());
let args = vec!["ex", "-gx"];
let config = create_config(args)?;
expect_that!(config.filter_git(), some(pat!(&GitFlags {
everything: true,
cached: false,
added: false,
modified: false,
renamed: false,
untracked: false,
ignored: false,
})));
let args = vec!["ex", "-gc"];
let config = create_config(args)?;
expect_that!(config.filter_git(), some(pat!(&GitFlags {
everything: false,
cached: true,
added: false,
modified: false,
renamed: false,
untracked: false,
ignored: false,
})));
let args = vec!["ex", "-ga"];
let config = create_config(args)?;
expect_that!(config.filter_git(), some(pat!(&GitFlags {
everything: false,
cached: false,
added: true,
modified: false,
renamed: false,
untracked: false,
ignored: false,
})));
let args = vec!["ex", "-gm"];
let config = create_config(args)?;
expect_that!(config.filter_git(), some(pat!(&GitFlags {
everything: false,
cached: false,
added: false,
modified: true,
renamed: false,
untracked: false,
ignored: false,
})));
let args = vec!["ex", "-gr"];
let config = create_config(args)?;
expect_that!(config.filter_git(), some(pat!(&GitFlags {
everything: false,
cached: false,
added: false,
modified: false,
renamed: true,
untracked: false,
ignored: false,
})));
let args = vec!["ex", "-gu"];
let config = create_config(args)?;
expect_that!(config.filter_git(), some(pat!(&GitFlags {
everything: false,
cached: false,
added: false,
modified: false,
renamed: false,
untracked: true,
ignored: false,
})));
let args = vec!["ex", "-gi"];
let config = create_config(args)?;
expect_that!(config.filter_git(), some(pat!(&GitFlags {
everything: false,
cached: false,
added: false,
modified: false,
renamed: false,
untracked: false,
ignored: true,
})));
let args = vec!["ex", "--git=amr"];
let config = create_config(args)?;
expect_that!(config.filter_git(), some(pat!(&GitFlags {
everything: false,
cached: false,
added: true,
modified: true,
renamed: true,
untracked: false,
ignored: false,
})));
Ok(())
}
#[gtest]
fn test_precise_is_handled() -> MyResult<()> {
let args = vec!["ex"];
let config = create_config(args)?;
expect_false!(config.show_precise());
let args = vec!["ex", "-p"];
let config = create_config(args)?;
expect_true!(config.show_precise());
let args = vec!["ex", "--precise"];
let config = create_config(args)?;
expect_true!(config.show_precise());
Ok(())
}
#[gtest]
fn test_utc_is_handled() -> MyResult<()> {
let args = vec!["ex"];
let config = create_config(args)?;
expect_false!(config.show_utc());
let args = vec!["ex", "-u"];
let config = create_config(args)?;
expect_true!(config.show_utc());
let args = vec!["ex", "--utc"];
let config = create_config(args)?;
expect_true!(config.show_utc());
Ok(())
}
#[gtest]
fn test_total_is_handled() -> MyResult<()> {
let args = vec!["ex"];
let config = create_config(args)?;
expect_false!(config.show_total());
let args = vec!["ex", "--total"];
let config = create_config(args)?;
expect_true!(config.show_total());
Ok(())
}
#[gtest]
#[cfg(unix)]
fn test_owner_is_handled() -> MyResult<()> {
let args = vec!["ex"];
let config = create_config(args)?;
expect_false!(config.show_owner());
let args = vec!["ex", "--owner"];
let config = create_config(args)?;
expect_true!(config.show_owner());
Ok(())
}
#[gtest]
fn test_data_is_handled() -> MyResult<()> {
let args = vec!["ex"];
let config = create_config(args)?;
expect_false!(config.show_sig());
let args = vec!["ex", "--sig"];
let config = create_config(args)?;
expect_true!(config.show_sig());
Ok(())
}
#[gtest]
fn test_only_path_is_handled_with_terminal() -> MyResult<()> {
let args = vec!["ex"];
let config = create_config_with_piped(args, false)?;
expect_false!(config.only_path()); expect_false!(config.escape_path()); expect_false!(config.null_path());
let args = vec!["ex", "-x"];
let config = create_config_with_piped(args, false)?;
expect_true!(config.only_path());
expect_false!(config.escape_path());
expect_false!(config.null_path());
let args = vec!["ex", "-x", "-x"];
let config = create_config_with_piped(args, false)?;
expect_false!(config.only_path());
expect_false!(config.escape_path());
expect_false!(config.null_path());
let args = vec!["ex", "-xx"];
let config = create_config_with_piped(args, false)?;
expect_false!(config.only_path());
expect_false!(config.escape_path());
expect_false!(config.null_path());
let args = vec!["ex", "--only-path"];
let config = create_config_with_piped(args, false)?;
expect_true!(config.only_path());
expect_false!(config.escape_path());
expect_false!(config.null_path());
Ok(())
}
#[gtest]
fn test_only_path_is_handled_with_piped() -> MyResult<()> {
let args = vec!["ex"];
let config = create_config_with_piped(args, true)?;
expect_true!(config.only_path()); expect_true!(config.escape_path()); expect_false!(config.null_path());
let args = vec!["ex", "-x"];
let config = create_config_with_piped(args, true)?;
expect_true!(config.only_path());
expect_false!(config.escape_path());
expect_false!(config.null_path());
let args = vec!["ex", "-x", "-x"];
let config = create_config_with_piped(args, true)?;
expect_false!(config.only_path());
expect_false!(config.escape_path());
expect_false!(config.null_path());
let args = vec!["ex", "-xx"];
let config = create_config_with_piped(args, true)?;
expect_false!(config.only_path());
expect_false!(config.escape_path());
expect_false!(config.null_path());
let args = vec!["ex", "--only-path"];
let config = create_config_with_piped(args, true)?;
expect_true!(config.only_path());
expect_false!(config.escape_path());
expect_false!(config.null_path());
Ok(())
}
#[gtest]
#[cfg(debug_assertions)]
fn test_only_path_is_handled_with_override() -> MyResult<()> {
let args = vec!["ex", "--terminal"];
let config = create_config_with_piped(args, true)?;
expect_false!(config.only_path()); expect_false!(config.escape_path()); expect_false!(config.null_path());
let args = vec!["ex", "--terminal", "-x"];
let config = create_config_with_piped(args, true)?;
expect_true!(config.only_path());
expect_false!(config.escape_path());
expect_false!(config.null_path());
let args = vec!["ex", "--terminal", "-x", "-x"];
let config = create_config_with_piped(args, true)?;
expect_false!(config.only_path());
expect_false!(config.escape_path());
expect_false!(config.null_path());
let args = vec!["ex", "--terminal", "-xx"];
let config = create_config_with_piped(args, true)?;
expect_false!(config.only_path());
expect_false!(config.escape_path());
expect_false!(config.null_path());
let args = vec!["ex", "--terminal", "--only-path"];
let config = create_config_with_piped(args, true)?;
expect_true!(config.only_path());
expect_false!(config.escape_path());
expect_false!(config.null_path());
Ok(())
}
#[gtest]
fn test_null_path_is_handled() -> MyResult<()> {
let args = vec!["ex"];
let config = create_config_with_piped(args, false)?;
expect_false!(config.only_path());
expect_false!(config.escape_path());
expect_false!(config.null_path());
let args = vec!["ex", "-z"]; let config = create_config_with_piped(args, false)?;
expect_false!(config.only_path());
expect_false!(config.escape_path());
expect_false!(config.null_path());
let args = vec!["ex", "--null-path"];
let config = create_config_with_piped(args, false)?;
expect_true!(config.only_path());
expect_false!(config.escape_path());
expect_true!(config.null_path());
Ok(())
}
#[gtest]
fn test_abs_path_is_handled() -> MyResult<()> {
let args = vec!["ex"];
let config = create_config(args)?;
expect_false!(config.abs_path());
let args = vec!["ex", "-q"];
let config = create_config(args)?;
expect_true!(config.abs_path());
let args = vec!["ex", "--abs-path"];
let config = create_config(args)?;
expect_true!(config.abs_path());
Ok(())
}
#[gtest]
#[cfg(windows)]
fn test_win_path_is_handled() -> MyResult<()> {
let args = vec!["ex"];
let config = create_config(args)?;
expect_false!(config.win_path());
let args = vec!["ex", "-w"];
let config = create_config(args)?;
expect_true!(config.win_path());
let args = vec!["ex", "--win-path"];
let config = create_config(args)?;
expect_true!(config.win_path());
Ok(())
}
#[gtest]
#[cfg(windows)]
fn test_win_ver_is_handled() -> MyResult<()> {
let args = vec!["ex"];
let config = create_config(args)?;
expect_false!(config.win_ver());
let args = vec!["ex", "-v"];
let config = create_config(args)?;
expect_true!(config.win_ver());
let args = vec!["ex", "--win-ver"];
let config = create_config(args)?;
expect_true!(config.win_ver());
Ok(())
}
#[gtest]
fn test_patterns_are_handled() -> MyResult<()> {
let args = vec!["ex"];
let config = create_config(args)?;
expect_that!(config.patterns(), elements_are!["."]);
let args = vec!["ex", "file1"];
let config = create_config(args)?;
expect_that!(config.patterns(), elements_are!["file1"]);
let args = vec!["ex", "file1", "file2"];
let config = create_config(args)?;
expect_that!(config.patterns(), elements_are!["file1", "file2"]);
Ok(())
}
#[gtest]
fn test_unexpected_depth_causes_error() {
let args = vec!["ex", "-dfoo"];
let result = create_config(args);
expect_that!(result, err(displays_as(contains_substring("Invalid depth option: foo"))));
}
#[gtest]
fn test_unexpected_order_causes_error() {
let args = vec!["ex", "-ofoo"];
let result = create_config(args);
expect_that!(result, err(displays_as(contains_substring("Invalid order option: foo"))));
}
#[gtest]
fn test_unexpected_recent_causes_error() {
let args = vec!["ex", "-rfoo"];
let result = create_config(args);
expect_that!(result, err(displays_as(contains_substring("Invalid recent option: foo"))));
}
#[gtest]
fn test_unexpected_type_causes_error() {
let args = vec!["ex", "-tfzd"];
let result = create_config(args);
expect_that!(result, err(displays_as(contains_substring("Invalid type option: z"))));
}
#[gtest]
fn test_unexpected_git_causes_error() {
let args = vec!["ex", "-gazm"];
let result = create_config(args);
expect_that!(result, err(displays_as(contains_substring("Invalid git option: z"))));
}
fn create_config(args: Vec<&str>) -> MyResult<Config> {
create_config_with_piped(args, false)
}
fn create_config_with_piped(args: Vec<&str>, piped: bool) -> MyResult<Config> {
let args = args.into_iter().map(String::from).collect();
Config::new(args, piped, DateTime::default)
}
impl Config {
pub fn with_curr_time(
mut self,
year: i32,
month: u32,
day: u32,
hour: u32,
minute: u32,
second: u32,
) -> Self {
self.curr_time = create_time(year, month, day, hour, minute, second).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<PeriodKind>) -> 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_crc(mut self, show_crc: bool) -> Self {
self.cli.show_crc = show_crc;
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
}
}
}