Skip to main content

ex_cli/
printer.rs

1use crate::cli::file::{ExecKind, FileKind};
2use crate::cli::recent::RecentKind;
3use crate::config::Config;
4use crate::error::MyResult;
5use crate::fs::file::{File, Signature};
6use crate::fs::total::Total;
7use crate::git::flags::GitFlags;
8use crate::regex;
9use crate::util::calendar::Calendar;
10use crate::util::color::ColorMap;
11use chrono::*;
12#[cfg(windows)]
13use regex::Captures;
14use std::collections::HashMap;
15use std::ffi::OsStr;
16use std::path::{Component, Path, PathBuf};
17#[cfg(unix)]
18use std::rc::Rc;
19use std::{cmp, path};
20use termcolor::WriteColor;
21
22const MODE_WIDTH: usize = 10; // (width of "drwxrwxrwx")
23const GIT_WIDTH: usize = 5; // (width of "AMRUI")
24const TIME_WIDTH: usize = 24; // (width of "Sun 31-Dec-2023 23:59:59")
25const MONTH_WIDTH: usize = 8; // (width of "12 month")
26const SIG_WIDTH: usize = 13; // (width of "41424344 ABCD")
27const PAD_WIDTH: usize = 2; // (width of "  ")
28
29pub struct IndentChars {
30    pub branching: char,
31    pub terminating: char,
32    pub horizontal: char,
33    pub vertical: char,
34}
35
36enum IndentToken {
37    BranchMiddle,
38    BranchFinal,
39    SpaceMiddle,
40    SpaceFinal,
41}
42
43#[allow(dead_code)]
44pub struct Printer<'a, W: WriteColor> {
45    config: &'a Config,
46    calendar: Calendar,
47    writer: W,
48    counter: HashMap<PathBuf, isize>,
49    colors: ColorMap,
50    chars: IndentChars,
51    git_bash: bool,
52    separator: char,
53    separator_str: String,
54}
55
56impl<'a, W: WriteColor> Printer<'a, W> {
57    pub fn new<Tz: TimeZone>(
58        config: &'a Config,
59        zone: &Tz,
60        writer: W,
61        colors: ColorMap,
62        chars: IndentChars,
63        git_bash: bool,
64    ) -> Self {
65        let calendar = Calendar::from_time(config.curr_time(), zone);
66        let counter = HashMap::new();
67        #[cfg(windows)]
68        let git_bash = git_bash && !config.win_path();
69        let separator = if git_bash { '/' } else { path::MAIN_SEPARATOR };
70        let separator_str = separator.to_string();
71        Self {
72            config,
73            calendar,
74            writer,
75            counter,
76            colors,
77            chars,
78            git_bash,
79            separator,
80            separator_str,
81        }
82    }
83
84    pub fn print_files<Tz: TimeZone>(
85        &mut self,
86        files: &Vec<File>,
87        total: &Total,
88        zone: &Tz,
89    ) -> MyResult<()> {
90        if self.config.show_indent() {
91            self.count_parents(files);
92        }
93        if self.config.only_path() {
94            for file in files {
95                self.print_path(file, false)?;
96                self.print_newline()?;
97            }
98        } else {
99            let mode_width = measure_mode(self.config);
100            let size_width = if self.config.show_total() {
101                measure_size(self.config, total.total_size)
102            } else {
103                measure_size(self.config, total.max_size)
104            };
105            let time_width = measure_time(self.config);
106            if self.config.filter_recent() != RecentKind::None {
107                self.print_start(total, zone, mode_width, size_width, time_width)?;
108            }
109            for file in files {
110                self.print_file(file, total, zone, size_width)?;
111            }
112            if self.config.show_total() {
113                self.print_total(total, mode_width, size_width, time_width)?;
114            }
115        }
116        Ok(())
117    }
118
119    #[allow(unused_mut)]
120    fn print_start<Tz: TimeZone>(
121        &mut self,
122        total: &Total,
123        zone: &Tz,
124        mode_width: usize,
125        size_width: usize,
126        time_width: usize,
127    ) -> MyResult<()> {
128        if let Some(start_time) = &total.start_time {
129            let mut combined_width = mode_width + PAD_WIDTH + size_width;
130            if self.config.filter_git().is_some() {
131                combined_width += 1 + GIT_WIDTH;
132            }
133            #[cfg(unix)]
134            if self.config.show_owner() {
135                combined_width += PAD_WIDTH + total.user_width + 1 + total.group_width;
136            }
137            self.print_text("Start", combined_width)?;
138            self.print_time(start_time, zone, false)?;
139            writeln!(self.writer)?;
140            self.print_hyphens(combined_width + PAD_WIDTH + time_width)?;
141        }
142        Ok(())
143    }
144
145    fn print_file<Tz: TimeZone>(
146        &mut self,
147        file: &File,
148        total: &Total,
149        zone: &Tz,
150        size_width: usize,
151    ) -> MyResult<()> {
152        self.print_mode(file.file_type, file.file_mode, file.inner_depth)?;
153        self.print_git(file.git_flags)?;
154        #[cfg(unix)]
155        self.print_owner(&file.owner_user, &file.owner_group, total.user_width, total.group_width)?;
156        self.print_size(file.file_size, size_width)?;
157        self.print_time(&file.file_time, zone, true)?;
158        self.print_sig(file.file_sig)?;
159        #[cfg(windows)]
160        self.print_version(&file.file_ver, total.ver_width)?;
161        self.print_ext(&file.file_ext, total.ext_width)?;
162        #[cfg(debug_assertions)]
163        self.print_debug(file.file_depth, file.inner_depth)?;
164        self.print_path(file, true)?;
165        writeln!(self.writer)?;
166        Ok(())
167    }
168
169    #[allow(unused_mut)]
170    fn print_total(
171        &mut self,
172        total: &Total,
173        mode_width: usize,
174        size_width: usize,
175        time_width: usize,
176    ) -> MyResult<()> {
177        let mut combined_width = mode_width;
178        if self.config.filter_git().is_some() {
179            combined_width += 1 + GIT_WIDTH;
180        }
181        #[cfg(unix)]
182        if self.config.show_owner() {
183            combined_width += PAD_WIDTH + total.user_width + 1 + total.group_width;
184        }
185        self.print_hyphens(combined_width + PAD_WIDTH + size_width + PAD_WIDTH + time_width)?;
186        self.print_text("Total", combined_width)?;
187        self.print_size(total.total_size, size_width)?;
188        self.print_spaces(PAD_WIDTH + PAD_WIDTH + time_width)?;
189        if self.config.show_sig() {
190            self.print_spaces(PAD_WIDTH + SIG_WIDTH)?;
191        }
192        if total.ext_width > 0 {
193            self.print_spaces(PAD_WIDTH + total.ext_width)?;
194        }
195        self.print_summary(total)?;
196        writeln!(self.writer)?;
197        Ok(())
198    }
199
200    fn print_summary(
201        &mut self,
202        total: &Total,
203    ) -> MyResult<()> {
204        let files = if total.num_files == 1 { "file" } else { "files" };
205        let dirs = if total.num_dirs == 1 { "directory" } else { "directories" };
206        write!(
207            self.writer,
208            "{num_files} {files} {num_dirs} {dirs}",
209            num_files = total.num_files,
210            num_dirs = total.num_dirs,
211        )?;
212        Ok(())
213    }
214
215    fn print_mode(
216        &mut self,
217        file_type: FileKind,
218        file_mode: u32,
219        inner_depth: Option<usize>,
220    ) -> MyResult<()> {
221        if self.config.zip_expand() {
222            if inner_depth.is_some() {
223                write!(self.writer, "z")?;
224            } else {
225                write!(self.writer, "-")?;
226            }
227        }
228        match file_type {
229            FileKind::File(_) => write!(self.writer, "-")?,
230            FileKind::Dir => write!(self.writer, "d")?,
231            FileKind::Link(_) => write!(self.writer, "l")?,
232            FileKind::Other => write!(self.writer, "?")?,
233        };
234        for shift in [6, 3, 0] {
235            let file_mode = file_mode >> shift;
236            if (file_mode & 4) != 0 {
237                write!(self.writer, "r")?;
238            } else {
239                write!(self.writer, "-")?;
240            }
241            if (file_mode & 2) != 0 {
242                write!(self.writer, "w")?;
243            } else {
244                write!(self.writer, "-")?;
245            }
246            if (file_mode & 1) != 0 {
247                write!(self.writer, "x")?;
248            } else {
249                write!(self.writer, "-")?;
250            }
251        }
252        Ok(())
253    }
254
255    fn print_git(
256        &mut self,
257        git_flags: Option<GitFlags>,
258    ) -> MyResult<()> {
259        if self.config.filter_git().is_some() {
260            if let Some(git_flags) = git_flags {
261                write!(self.writer, " ")?;
262                write!(self.writer, "{}", if git_flags.added { 'A' } else { '-' })?;
263                write!(self.writer, "{}", if git_flags.modified { 'M' } else { '-' })?;
264                write!(self.writer, "{}", if git_flags.renamed { 'R' } else { '-' })?;
265                write!(self.writer, "{}", if git_flags.untracked { 'U' } else { '-' })?;
266                write!(self.writer, "{}", if git_flags.ignored { 'I' } else { '-' })?;
267            } else {
268                write!(self.writer, " -----")?;
269            }
270        }
271        Ok(())
272    }
273
274    #[cfg(unix)]
275    fn print_owner(
276        &mut self,
277        owner_user: &Option<Rc<String>>,
278        owner_group: &Option<Rc<String>>,
279        user_width: usize,
280        group_width: usize,
281    ) -> MyResult<()> {
282        if self.config.show_owner() {
283            self.print_spaces(PAD_WIDTH)?;
284            if let Some(user) = owner_user {
285                write!(self.writer, "{0:1$}", user, user_width + 1)?;
286            } else {
287                write!(self.writer, "{0:1$}", "-", user_width + 1)?;
288            }
289            if let Some(group) = owner_group {
290                write!(self.writer, "{0:1$}", group, group_width)?;
291            } else {
292                write!(self.writer, "{0:1$}", "-", group_width)?;
293            }
294        }
295        Ok(())
296    }
297
298    fn print_size(
299        &mut self,
300        file_size: u64,
301        size_width: usize,
302    ) -> MyResult<()> {
303        self.print_spaces(PAD_WIDTH)?;
304        if self.config.show_precise() {
305            self.print_thousand(file_size, size_width)?;
306        } else {
307            if file_size < 1_000 {
308                write!(self.writer, "{0:3} B ", file_size)?;
309            } else if file_size < 1_000_000 {
310                write!(self.writer, "{0:3} KB", file_size / 1_000)?;
311            } else if file_size < 1_000_000_000 {
312                write!(self.writer, "{0:3} MB", file_size / 1_000_000)?;
313            } else if file_size < 1_000_000_000_000 {
314                write!(self.writer, "{0:3} GB", file_size / 1_000_000_000)?;
315            } else if file_size < 1_000_000_000_000_000 {
316                write!(self.writer, "{0:3} TB", file_size / 1_000_000_000_000)?;
317            } else if file_size < 1_000_000_000_000_000_000 {
318                write!(self.writer, "{0:3} PB", file_size / 1_000_000_000_000_000)?;
319            } else {
320                write!(self.writer, "{0:3} EB", file_size / 1_000_000_000_000_000_000)?;
321            }
322        }
323        Ok(())
324    }
325
326    fn print_thousand(
327        &mut self,
328        file_size: u64,
329        size_width: usize,
330    ) -> MyResult<()> {
331        if file_size >= 1000 {
332            self.print_thousand(file_size / 1000, cmp::max(size_width, 4) - 4)?;
333            write!(self.writer, ",{0:03}", file_size % 1000)?;
334        } else {
335            write!(self.writer, "{0:1$}", file_size, size_width)?;
336        }
337        Ok(())
338    }
339
340    fn print_time<Tz: TimeZone>(
341        &mut self,
342        file_time: &DateTime<Utc>,
343        zone: &Tz,
344        padding: bool,
345    ) -> MyResult<()> {
346        self.print_spaces(PAD_WIDTH)?;
347        if self.config.show_precise() {
348            if file_time.timestamp() != 0 {
349                let file_time = file_time.with_timezone(zone);
350                let weekday = convert_weekday(file_time.weekday());
351                let day = file_time.day();
352                let month = convert_month(file_time.month());
353                let year = file_time.year();
354                let hour = file_time.hour();
355                let minute = file_time.minute();
356                let second = file_time.second();
357                write!(self.writer, "{weekday} {day:02}-{month}-{year:04} {hour:02}:{minute:02}:{second:02}")?;
358                if self.config.show_utc() {
359                    write!(self.writer, "Z")?;
360                }
361            } else {
362                write!(self.writer, "{0:-<1$}", "", TIME_WIDTH)?;
363                if self.config.show_utc() {
364                    write!(self.writer, "-")?;
365                }
366            }
367        } else {
368            if file_time.timestamp() != 0 {
369                let recent = RecentKind::from_times(&file_time, self.config.curr_time(), &self.calendar, zone);
370                match recent {
371                    RecentKind::None => write!(self.writer, " future")?,
372                    RecentKind::Sec(count) => write!(self.writer, "{:2} sec", count)?,
373                    RecentKind::Min(count) => write!(self.writer, "{:2} min", count)?,
374                    RecentKind::Hour(count) => write!(self.writer, "{:2} hour", count)?,
375                    RecentKind::Day(count) => write!(self.writer, "{:2} day", count)?,
376                    RecentKind::Week(count) => write!(self.writer, "{:2} week", count)?,
377                    RecentKind::Month(count) => write!(self.writer, "{:2} month", count)?,
378                    RecentKind::Year(count) => write!(self.writer, "{:2} year", count)?,
379                }
380                if padding {
381                    match recent {
382                        RecentKind::None => write!(self.writer, " ")?,
383                        RecentKind::Sec(_) => write!(self.writer, "  ")?,
384                        RecentKind::Min(_) => write!(self.writer, "  ")?,
385                        RecentKind::Hour(_) => write!(self.writer, " ")?,
386                        RecentKind::Day(_) => write!(self.writer, "  ")?,
387                        RecentKind::Week(_) => write!(self.writer, " ")?,
388                        RecentKind::Month(_) => (),
389                        RecentKind::Year(_) => write!(self.writer, " ")?,
390                    }
391                }
392            } else {
393                write!(self.writer, "{0:-<1$}", "", MONTH_WIDTH)?;
394            }
395        }
396        Ok(())
397    }
398
399    fn print_sig(&mut self, file_sig: Signature) -> MyResult<()> {
400        if self.config.show_sig() {
401            self.print_spaces(PAD_WIDTH)?;
402            for byte in file_sig {
403                write!(self.writer, "{:02x}", byte)?;
404            }
405            write!(self.writer, " ")?;
406            for byte in file_sig {
407                write!(self.writer, "{}", printable_char(byte))?;
408            }
409        }
410        Ok(())
411    }
412
413    #[cfg(windows)]
414    fn print_version(
415        &mut self,
416        file_ver: &Option<String>,
417        ver_width: usize,
418    ) -> MyResult<()> {
419        if ver_width > 0 {
420            self.print_spaces(PAD_WIDTH)?;
421            if let Some(file_ver) = file_ver {
422                write!(self.writer, "{0:1$}", file_ver, ver_width)?;
423            } else {
424                self.print_spaces(ver_width)?;
425            }
426        }
427        Ok(())
428    }
429
430    fn print_ext(
431        &mut self,
432        file_ext: &str,
433        ext_width: usize,
434    ) -> MyResult<()> {
435        if ext_width > 0 {
436            self.print_spaces(PAD_WIDTH)?;
437            write!(self.writer, "{0:1$}", file_ext, ext_width)?;
438        }
439        Ok(())
440    }
441
442    #[cfg(debug_assertions)]
443    fn print_debug(
444        &mut self,
445        file_depth: usize,
446        inner_depth: Option<usize>,
447    ) -> MyResult<()> {
448        if self.config.show_debug() {
449            self.writer.set_color(&self.colors.debug_color)?;
450            if self.config.zip_expand() {
451                let inner_depth = inner_depth
452                    .map(|depth| depth.to_string())
453                    .unwrap_or_else(|| "-".to_string());
454                write!(self.writer, "[{}][{}]", file_depth, inner_depth)?;
455            } else {
456                write!(self.writer, "[{}]", file_depth)?;
457            }
458            self.writer.reset()?;
459            write!(self.writer, " ")?;
460        }
461        Ok(())
462    }
463
464    fn print_path(
465        &mut self,
466        file: &File,
467        padding: bool,
468    ) -> MyResult<()> {
469        if padding {
470            self.print_spaces(PAD_WIDTH)?;
471        }
472        if self.config.show_indent() {
473            self.print_prefix(file)?;
474            if file.file_type == FileKind::Dir {
475                self.indent_dir(&file.rel_dir, file.inner_depth, file.file_type.dir_offset())?;
476            } else {
477                self.print_name(&file.file_name, &file.file_ext, file.file_type)?;
478            }
479            self.print_link(&file.link_data)?;
480        } else {
481            let file_dir = file.select_dir(self.config.abs_path());
482            if self.config.sort_name() {
483                self.print_name(&file.file_name, &file.file_ext, file.file_type)?;
484                self.print_dir(file_dir, file.inner_depth, file.file_type.dir_offset(), true)?;
485                self.print_link(&file.link_data)?;
486            } else {
487                self.print_dir(file_dir, file.inner_depth, file.file_type.dir_offset(), false)?;
488                self.print_name(&file.file_name, &file.file_ext, file.file_type)?;
489                if !self.config.escape_path() && !self.config.null_path() {
490                    self.print_link(&file.link_data)?;
491                }
492            }
493        }
494        Ok(())
495    }
496
497    fn print_dir(
498        &mut self,
499        file_dir: &Path,
500        inner_depth: Option<usize>,
501        inner_offset: usize,
502        sort_name: bool,
503    ) -> MyResult<()> {
504        if !is_trivial(file_dir) {
505            if sort_name {
506                write!(self.writer, " (")?;
507                self.iterate_dir(file_dir, inner_depth, inner_offset)?;
508                write!(self.writer, ")")?;
509            } else {
510                self.iterate_dir(file_dir, inner_depth, inner_offset)?;
511            }
512        }
513        Ok(())
514    }
515
516    fn iterate_dir(
517        &mut self,
518        file_dir: &Path,
519        inner_depth: Option<usize>,
520        inner_offset: usize,
521    ) -> MyResult<()> {
522        self.writer.set_color(&self.colors.dir_color)?;
523        let components = file_dir.components().into_iter().collect::<Vec<_>>();
524        let count = components.len();
525        for (index, component) in components.iter().enumerate() {
526            if let Some(text) = component.as_os_str().to_str() {
527                let color = inner_depth
528                    .is_some_and(|depth| depth + inner_offset + index == count)
529                    .then(|| get_extension(component))
530                    .and_then(|ext| self.colors.find_color(ext));
531                if let Some(color) = color {
532                    self.writer.set_color(color)?;
533                    self.escape_dir(text)?;
534                    self.writer.set_color(&self.colors.dir_color)?;
535                } else {
536                    self.escape_dir(text)?;
537                }
538                if is_joinable(&component) {
539                    write!(self.writer, "{}", self.separator)?;
540                }
541            }
542        }
543        self.writer.reset()?;
544        Ok(())
545    }
546
547    fn indent_dir(
548        &mut self,
549        file_dir: &Path,
550        inner_depth: Option<usize>,
551        inner_offset: usize,
552    ) -> MyResult<()> {
553        if let Some(component) = file_dir.components().last() {
554            if let Some(text) = component.as_os_str().to_str() {
555                let color = inner_depth
556                    .is_some_and(|depth| depth + inner_offset == 1)
557                    .then(|| get_extension(&component))
558                    .and_then(|ext| self.colors.find_color(ext))
559                    .unwrap_or(&self.colors.dir_color);
560                self.writer.set_color(color)?;
561                self.escape_dir(text)?;
562                self.writer.reset()?;
563            }
564        }
565        Ok(())
566    }
567
568    #[cfg(windows)]
569    fn escape_dir(
570        &mut self,
571        file_dir: &str,
572    ) -> MyResult<()> {
573        if self.git_bash {
574            let drive_regex = regex!(r#"^([A-Z]):(.*)$"#);
575            let file_dir = file_dir.replace(path::MAIN_SEPARATOR, &self.separator_str);
576            let file_dir = drive_regex.replace(&file_dir, |caps: &Captures| {
577                format!("{}{}{}", self.separator, &caps[1].to_lowercase(), &caps[2])
578            });
579            if self.config.escape_path() {
580                let escape_regex = regex!(r#"([\s"'])"#);
581                let file_dir = escape_regex.replace_all(&file_dir, "\\$1");
582                write!(self.writer, "{file_dir}")?;
583            } else {
584                write!(self.writer, "{file_dir}")?;
585            }
586        } else {
587            write!(self.writer, "{file_dir}")?;
588        }
589        Ok(())
590    }
591
592    #[cfg(not(windows))]
593    fn escape_dir(
594        &mut self,
595        file_dir: &str,
596    ) -> MyResult<()> {
597        if self.config.escape_path() {
598            let escape_regex = regex!(r#"([\s"'\\])"#);
599            let file_dir = escape_regex.replace_all(file_dir, "\\$1");
600            write!(self.writer, "{file_dir}")?;
601        } else {
602            write!(self.writer, "{file_dir}")?;
603        }
604        Ok(())
605    }
606
607    fn print_name(
608        &mut self,
609        file_name: &str,
610        file_ext: &str,
611        file_type: FileKind,
612    ) -> MyResult<()> {
613        if !file_name.is_empty() {
614            match file_type {
615                FileKind::File(exec) => {
616                    if exec == ExecKind::User {
617                        self.writer.set_color(&self.colors.exec_color)?;
618                        self.escape_name(file_name)?;
619                        self.writer.reset()?;
620                    } else if exec == ExecKind::Other {
621                        self.writer.set_color(&self.colors.exec_other)?;
622                        self.escape_name(file_name)?;
623                        self.writer.reset()?;
624                    } else if let Some(color) = self.colors.find_color(file_ext) {
625                        self.writer.set_color(color)?;
626                        self.escape_name(file_name)?;
627                        self.writer.reset()?;
628                    } else {
629                        self.escape_name(file_name)?;
630                    }
631                }
632                FileKind::Dir => {
633                    self.writer.set_color(&self.colors.dir_color)?;
634                    self.escape_name(file_name)?;
635                    write!(self.writer, "{}", self.separator)?;
636                    self.writer.reset()?;
637                }
638                FileKind::Link(resolved) => {
639                    if resolved {
640                        self.writer.set_color(&self.colors.link_color)?;
641                    } else {
642                        self.writer.set_color(&self.colors.bad_color)?;
643                    }
644                    self.escape_name(file_name)?;
645                    self.writer.reset()?;
646                }
647                FileKind::Other => {
648                    self.escape_name(file_name)?;
649                }
650            }
651        }
652        Ok(())
653    }
654
655    #[cfg(windows)]
656    fn escape_name(
657        &mut self,
658        file_name: &str,
659    ) -> MyResult<()> {
660        if self.config.escape_path() && self.git_bash {
661            let escape_regex = regex!(r#"([\s"'])"#);
662            let file_name = escape_regex.replace_all(file_name, "\\$1");
663            write!(self.writer, "{file_name}")?;
664        } else {
665            write!(self.writer, "{file_name}")?;
666        }
667        Ok(())
668    }
669
670    #[cfg(not(windows))]
671    fn escape_name(
672        &mut self,
673        file_name: &str,
674    ) -> MyResult<()> {
675        if self.config.escape_path() {
676            let escape_regex = regex!(r#"([\s"'\\])"#);
677            let file_name = escape_regex.replace_all(file_name, "\\$1");
678            write!(self.writer, "{file_name}")?;
679        } else {
680            write!(self.writer, "{file_name}")?;
681        }
682        Ok(())
683    }
684
685    fn print_link(
686        &mut self,
687        link_data: &Option<(PathBuf, FileKind)>,
688    ) -> MyResult<()> {
689        if let Some((link_path, link_type)) = link_data {
690            if let Some(link_dir) = link_path.parent() {
691                if let Some(link_name) = link_path.file_name().and_then(OsStr::to_str) {
692                    write!(self.writer, " -> ")?;
693                    let link_ext = link_path.extension().and_then(OsStr::to_str).unwrap_or_default();
694                    self.print_dir(link_dir, None, 0, false)?;
695                    self.print_name(link_name, &link_ext, *link_type)?;
696                }
697            }
698        }
699        Ok(())
700    }
701
702    fn count_parents(&mut self, files: &Vec<File>) {
703        for file in files {
704            if file.file_depth > 1 {
705                if let Some(parent) = file.select_parent_for_indent() {
706                    let entry = self.counter.entry(parent).or_insert(0);
707                    *entry += 1;
708                }
709            }
710        }
711    }
712
713    fn print_prefix(&mut self, file: &File) -> MyResult<()> {
714        let tokens = self.create_prefix(file);
715        for token in tokens {
716            match token {
717                IndentToken::BranchMiddle => {
718                    write!(self.writer, " ")?;
719                    self.writer.set_color(&self.colors.dir_color)?;
720                    write!(self.writer, "{}", self.chars.branching)?;
721                    write!(self.writer, "{}", self.chars.horizontal)?;
722                    self.writer.reset()?;
723                    write!(self.writer, " ")?;
724                }
725                IndentToken::BranchFinal => {
726                    write!(self.writer, " ")?;
727                    self.writer.set_color(&self.colors.dir_color)?;
728                    write!(self.writer, "{}", self.chars.terminating)?;
729                    write!(self.writer, "{}", self.chars.horizontal)?;
730                    self.writer.reset()?;
731                    write!(self.writer, " ")?;
732                }
733                IndentToken::SpaceMiddle => {
734                    write!(self.writer, " ")?;
735                    self.writer.set_color(&self.colors.dir_color)?;
736                    write!(self.writer, "{}", self.chars.vertical)?;
737                    self.writer.reset()?;
738                    write!(self.writer, "  ")?;
739                }
740                IndentToken::SpaceFinal => {
741                    write!(self.writer, "    ")?;
742                }
743            }
744        }
745        Ok(())
746    }
747
748    fn create_prefix(&mut self, file: &File) -> Vec<IndentToken> {
749        let mut tokens = Vec::new();
750        if let Some(mut path) = file.select_parent_for_indent() {
751            if let Some(count) = self.counter.get_mut(&path) {
752                *count -= 1;
753                if *count > 0 {
754                    tokens.push(IndentToken::BranchMiddle);
755                } else {
756                    tokens.push(IndentToken::BranchFinal);
757                }
758            }
759            while let Some(parent) = path.parent() {
760                path = PathBuf::from(parent);
761                if let Some(count) = self.counter.get(&path) {
762                    if *count > 0 {
763                        tokens.push(IndentToken::SpaceMiddle);
764                    } else {
765                        tokens.push(IndentToken::SpaceFinal);
766                    }
767                }
768            }
769        }
770        tokens.reverse();
771        tokens
772    }
773
774    fn print_text(&mut self, text: &str, width: usize) -> MyResult<()> {
775        write!(self.writer, "{0:<1$}", text, width)?;
776        Ok(())
777    }
778
779    fn print_spaces(&mut self, width: usize) -> MyResult<()> {
780        write!(self.writer, "{0:<1$}", "", width)?;
781        Ok(())
782    }
783
784    fn print_hyphens(&mut self, width: usize) -> MyResult<()> {
785        writeln!(self.writer, "{0:-<1$}", "", width)?;
786        Ok(())
787    }
788
789    fn print_newline(&mut self) -> MyResult<()> {
790        if self.config.null_path() {
791            write!(self.writer, "\x00")?;
792        } else {
793            writeln!(self.writer)?;
794        }
795        Ok(())
796    }
797}
798
799fn measure_mode(config: &Config) -> usize {
800    if config.zip_expand() {
801        MODE_WIDTH + 1
802    } else {
803        MODE_WIDTH
804    }
805}
806
807fn measure_size(config: &Config, size: u64) -> usize {
808    if config.show_precise() {
809        recurse_size(size)
810    } else {
811        6
812    }
813}
814
815fn recurse_size(size: u64) -> usize {
816    if size >= 1000 {
817        recurse_size(size / 1000) + 4
818    } else {
819        3
820    }
821}
822
823fn measure_time(config: &Config) -> usize {
824    if config.show_precise() {
825        if config.show_utc() {
826            TIME_WIDTH + 1 // (with extra "Z")
827        } else {
828            TIME_WIDTH
829        }
830    } else {
831        MONTH_WIDTH
832    }
833}
834
835fn convert_weekday(weekday: Weekday) -> &'static str {
836    match weekday {
837        Weekday::Mon => "Mon",
838        Weekday::Tue => "Tue",
839        Weekday::Wed => "Wed",
840        Weekday::Thu => "Thu",
841        Weekday::Fri => "Fri",
842        Weekday::Sat => "Sat",
843        Weekday::Sun => "Sun",
844    }
845}
846
847fn convert_month(month: u32) -> &'static str {
848    match month {
849        1 => "Jan",
850        2 => "Feb",
851        3 => "Mar",
852        4 => "Apr",
853        5 => "May",
854        6 => "Jun",
855        7 => "Jul",
856        8 => "Aug",
857        9 => "Sep",
858        10 => "Oct",
859        11 => "Nov",
860        12 => "Dec",
861        _ => "???",
862    }
863}
864
865#[inline]
866fn printable_char(byte: u8) -> char {
867    if byte >= 32 && byte <= 126 { byte as char } else { '.' }
868}
869
870fn is_trivial(file_dir: &Path) -> bool {
871    let file_dir = file_dir.to_str().unwrap_or_default();
872    file_dir.is_empty() || file_dir == "."
873}
874
875fn is_joinable(component: &Component) -> bool {
876    match component {
877        Component::Prefix(_) => false,
878        Component::RootDir => false,
879        Component::CurDir => true,
880        Component::ParentDir => true,
881        Component::Normal(_) => true,
882    }
883}
884
885fn get_extension<'a>(component: &'a Component) -> &'a str {
886    let component = component.as_os_str();
887    let (_, ext) = rsplit_file_at_dot(component);
888    ext.and_then(OsStr::to_str).unwrap_or_default()
889}
890
891// Borrowed from standard library.
892fn rsplit_file_at_dot(file: &OsStr) -> (Option<&OsStr>, Option<&OsStr>) {
893    if file.as_encoded_bytes() == b".." {
894        (Some(file), None)
895    } else {
896        // The unsafety here stems from converting between &OsStr and &[u8]
897        // and back. This is safe to do because (1) we only look at ASCII
898        // contents of the encoding and (2) new &OsStr values are produced
899        // only from ASCII-bounded slices of existing &OsStr values.
900        let mut iter = file.as_encoded_bytes().rsplitn(2, |b| *b == b'.');
901        let after = iter.next();
902        let before = iter.next();
903        if before == Some(b"") {
904            (Some(file), None)
905        } else {
906            unsafe {
907                let before = before.map(|s| OsStr::from_encoded_bytes_unchecked(s));
908                let after = after.map(|s| OsStr::from_encoded_bytes_unchecked(s));
909                (before, after)
910            }
911        }
912    }
913}
914
915#[cfg(test)]
916mod tests {
917    use crate::cli::file::{ExecKind, FileKind};
918    use crate::cli::recent::RecentKind;
919    use crate::config::Config;
920    use crate::error::MyResult;
921    use crate::fs::file::File;
922    use crate::fs::total::Total;
923    use crate::git::flags::GitFlags;
924    use crate::printer::{measure_mode, measure_size, IndentChars, Printer};
925    use crate::util::color::ColorMap;
926    use chrono::{TimeZone, Utc};
927    use path_clean::PathClean;
928    use pretty_assertions::assert_eq;
929    use std::cmp::Ordering;
930    use std::io;
931    use std::io::Write;
932    use std::path::{Component, Path, PathBuf};
933    use termcolor::{Color, ColorSpec, WriteColor};
934
935    #[test]
936    fn test_measures_mode_no_expand() {
937        let config = Config::default()
938            .with_zip_expand(false);
939        assert_eq!(10, measure_mode(&config));
940    }
941
942    #[test]
943    fn test_measures_mode_with_expand() {
944        let config = Config::default()
945            .with_zip_expand(true);
946        assert_eq!(11, measure_mode(&config));
947    }
948
949    #[test]
950    fn test_prints_type_no_expand() {
951        assert_eq!("----------", wrap_mode(false, None, 0o000, FileKind::File(ExecKind::None)));
952        assert_eq!("----------", wrap_mode(false, None, 0o000, FileKind::File(ExecKind::User)));
953        assert_eq!("----------", wrap_mode(false, None, 0o000, FileKind::File(ExecKind::Other)));
954        assert_eq!("d---------", wrap_mode(false, None, 0o000, FileKind::Dir));
955        assert_eq!("l---------", wrap_mode(false, None, 0o000, FileKind::Link(false)));
956        assert_eq!("l---------", wrap_mode(false, None, 0o000, FileKind::Link(true)));
957        assert_eq!("?---------", wrap_mode(false, None, 0o000, FileKind::Other));
958        assert_eq!("----------", wrap_mode(false, Some(0), 0o000, FileKind::File(ExecKind::None)));
959        assert_eq!("----------", wrap_mode(false, Some(0), 0o000, FileKind::File(ExecKind::User)));
960        assert_eq!("----------", wrap_mode(false, Some(0), 0o000, FileKind::File(ExecKind::Other)));
961        assert_eq!("d---------", wrap_mode(false, Some(0), 0o000, FileKind::Dir));
962        assert_eq!("l---------", wrap_mode(false, Some(0), 0o000, FileKind::Link(false)));
963        assert_eq!("l---------", wrap_mode(false, Some(0), 0o000, FileKind::Link(true)));
964        assert_eq!("?---------", wrap_mode(false, Some(0), 0o000, FileKind::Other));
965    }
966
967    #[test]
968    fn test_prints_type_with_expand() {
969        assert_eq!("-----------", wrap_mode(true, None, 0o000, FileKind::File(ExecKind::None)));
970        assert_eq!("-----------", wrap_mode(true, None, 0o000, FileKind::File(ExecKind::User)));
971        assert_eq!("-----------", wrap_mode(true, None, 0o000, FileKind::File(ExecKind::Other)));
972        assert_eq!("-d---------", wrap_mode(true, None, 0o000, FileKind::Dir));
973        assert_eq!("-l---------", wrap_mode(true, None, 0o000, FileKind::Link(false)));
974        assert_eq!("-l---------", wrap_mode(true, None, 0o000, FileKind::Link(true)));
975        assert_eq!("-?---------", wrap_mode(true, None, 0o000, FileKind::Other));
976        assert_eq!("z----------", wrap_mode(true, Some(0), 0o000, FileKind::File(ExecKind::None)));
977        assert_eq!("z----------", wrap_mode(true, Some(0), 0o000, FileKind::File(ExecKind::User)));
978        assert_eq!("z----------", wrap_mode(true, Some(0), 0o000, FileKind::File(ExecKind::Other)));
979        assert_eq!("zd---------", wrap_mode(true, Some(0), 0o000, FileKind::Dir));
980        assert_eq!("zl---------", wrap_mode(true, Some(0), 0o000, FileKind::Link(false)));
981        assert_eq!("zl---------", wrap_mode(true, Some(0), 0o000, FileKind::Link(true)));
982        assert_eq!("z?---------", wrap_mode(true, Some(0), 0o000, FileKind::Other));
983    }
984
985    #[test]
986    fn test_prints_mode_no_expand() {
987        assert_eq!("----------", wrap_mode(false, None, 0o000, FileKind::File(ExecKind::None)));
988        assert_eq!("-r--------", wrap_mode(false, None, 0o400, FileKind::File(ExecKind::None)));
989        assert_eq!("--w-------", wrap_mode(false, None, 0o200, FileKind::File(ExecKind::None)));
990        assert_eq!("---x------", wrap_mode(false, None, 0o100, FileKind::File(ExecKind::None)));
991        assert_eq!("----r-----", wrap_mode(false, None, 0o040, FileKind::File(ExecKind::None)));
992        assert_eq!("-----w----", wrap_mode(false, None, 0o020, FileKind::File(ExecKind::None)));
993        assert_eq!("------x---", wrap_mode(false, None, 0o010, FileKind::File(ExecKind::None)));
994        assert_eq!("-------r--", wrap_mode(false, None, 0o004, FileKind::File(ExecKind::None)));
995        assert_eq!("--------w-", wrap_mode(false, None, 0o002, FileKind::File(ExecKind::None)));
996        assert_eq!("---------x", wrap_mode(false, None, 0o001, FileKind::File(ExecKind::None)));
997        assert_eq!("-rwxrwxrwx", wrap_mode(false, None, 0o777, FileKind::File(ExecKind::None)));
998        assert_eq!("----------", wrap_mode(false, Some(0), 0o000, FileKind::File(ExecKind::None)));
999        assert_eq!("-r--------", wrap_mode(false, Some(0), 0o400, FileKind::File(ExecKind::None)));
1000        assert_eq!("--w-------", wrap_mode(false, Some(0), 0o200, FileKind::File(ExecKind::None)));
1001        assert_eq!("---x------", wrap_mode(false, Some(0), 0o100, FileKind::File(ExecKind::None)));
1002        assert_eq!("----r-----", wrap_mode(false, Some(0), 0o040, FileKind::File(ExecKind::None)));
1003        assert_eq!("-----w----", wrap_mode(false, Some(0), 0o020, FileKind::File(ExecKind::None)));
1004        assert_eq!("------x---", wrap_mode(false, Some(0), 0o010, FileKind::File(ExecKind::None)));
1005        assert_eq!("-------r--", wrap_mode(false, Some(0), 0o004, FileKind::File(ExecKind::None)));
1006        assert_eq!("--------w-", wrap_mode(false, Some(0), 0o002, FileKind::File(ExecKind::None)));
1007        assert_eq!("---------x", wrap_mode(false, Some(0), 0o001, FileKind::File(ExecKind::None)));
1008        assert_eq!("-rwxrwxrwx", wrap_mode(false, Some(0), 0o777, FileKind::File(ExecKind::None)));
1009    }
1010
1011    #[test]
1012    fn test_prints_mode_with_expand() {
1013        assert_eq!("-----------", wrap_mode(true, None, 0o000, FileKind::File(ExecKind::None)));
1014        assert_eq!("--r--------", wrap_mode(true, None, 0o400, FileKind::File(ExecKind::None)));
1015        assert_eq!("---w-------", wrap_mode(true, None, 0o200, FileKind::File(ExecKind::None)));
1016        assert_eq!("----x------", wrap_mode(true, None, 0o100, FileKind::File(ExecKind::None)));
1017        assert_eq!("-----r-----", wrap_mode(true, None, 0o040, FileKind::File(ExecKind::None)));
1018        assert_eq!("------w----", wrap_mode(true, None, 0o020, FileKind::File(ExecKind::None)));
1019        assert_eq!("-------x---", wrap_mode(true, None, 0o010, FileKind::File(ExecKind::None)));
1020        assert_eq!("--------r--", wrap_mode(true, None, 0o004, FileKind::File(ExecKind::None)));
1021        assert_eq!("---------w-", wrap_mode(true, None, 0o002, FileKind::File(ExecKind::None)));
1022        assert_eq!("----------x", wrap_mode(true, None, 0o001, FileKind::File(ExecKind::None)));
1023        assert_eq!("--rwxrwxrwx", wrap_mode(true, None, 0o777, FileKind::File(ExecKind::None)));
1024        assert_eq!("z----------", wrap_mode(true, Some(0), 0o000, FileKind::File(ExecKind::None)));
1025        assert_eq!("z-r--------", wrap_mode(true, Some(0), 0o400, FileKind::File(ExecKind::None)));
1026        assert_eq!("z--w-------", wrap_mode(true, Some(0), 0o200, FileKind::File(ExecKind::None)));
1027        assert_eq!("z---x------", wrap_mode(true, Some(0), 0o100, FileKind::File(ExecKind::None)));
1028        assert_eq!("z----r-----", wrap_mode(true, Some(0), 0o040, FileKind::File(ExecKind::None)));
1029        assert_eq!("z-----w----", wrap_mode(true, Some(0), 0o020, FileKind::File(ExecKind::None)));
1030        assert_eq!("z------x---", wrap_mode(true, Some(0), 0o010, FileKind::File(ExecKind::None)));
1031        assert_eq!("z-------r--", wrap_mode(true, Some(0), 0o004, FileKind::File(ExecKind::None)));
1032        assert_eq!("z--------w-", wrap_mode(true, Some(0), 0o002, FileKind::File(ExecKind::None)));
1033        assert_eq!("z---------x", wrap_mode(true, Some(0), 0o001, FileKind::File(ExecKind::None)));
1034        assert_eq!("z-rwxrwxrwx", wrap_mode(true, Some(0), 0o777, FileKind::File(ExecKind::None)));
1035    }
1036
1037    #[test]
1038    fn test_measures_size_for_integer() {
1039        let config = Config::default()
1040            .with_show_precise(true);
1041        assert_eq!(3, measure_size(&config, 0));
1042        assert_eq!(3, measure_size(&config, 999));
1043        assert_eq!(7, measure_size(&config, 1_000));
1044        assert_eq!(7, measure_size(&config, 999_999));
1045        assert_eq!(11, measure_size(&config, 1_000_000));
1046        assert_eq!(11, measure_size(&config, 999_999_999));
1047    }
1048
1049    #[test]
1050    fn test_measures_size_for_si_units() {
1051        let config = Config::default()
1052            .with_show_precise(false);
1053        assert_eq!(6, measure_size(&config, 0));
1054        assert_eq!(6, measure_size(&config, 999));
1055        assert_eq!(6, measure_size(&config, 1_000));
1056        assert_eq!(6, measure_size(&config, 999_999));
1057        assert_eq!(6, measure_size(&config, 1_000_000));
1058        assert_eq!(6, measure_size(&config, 999_999_999));
1059    }
1060
1061    #[test]
1062    fn test_prints_unpadded_size_as_integer() {
1063        let config = Config::default()
1064            .with_show_precise(true);
1065        assert_eq!("  0", wrap_size(&config, 0, 0));
1066        assert_eq!("  9", wrap_size(&config, 9, 0));
1067        assert_eq!("  10", wrap_size(&config, 10, 0));
1068        assert_eq!("  99", wrap_size(&config, 99, 0));
1069        assert_eq!("  100", wrap_size(&config, 100, 0));
1070        assert_eq!("  999", wrap_size(&config, 999, 0));
1071        assert_eq!("  1,000", wrap_size(&config, 1_000, 0));
1072        assert_eq!("  9,999", wrap_size(&config, 9_999, 0));
1073        assert_eq!("  10,000", wrap_size(&config, 10_000, 0));
1074        assert_eq!("  99,999", wrap_size(&config, 99_999, 0));
1075        assert_eq!("  100,000", wrap_size(&config, 100_000, 0));
1076        assert_eq!("  999,999", wrap_size(&config, 999_999, 0));
1077        assert_eq!("  1,000,000", wrap_size(&config, 1_000_000, 0));
1078        assert_eq!("  9,999,999", wrap_size(&config, 9_999_999, 0));
1079        assert_eq!("  10,000,000", wrap_size(&config, 10_000_000, 0));
1080        assert_eq!("  99,999,999", wrap_size(&config, 99_999_999, 0));
1081        assert_eq!("  100,000,000", wrap_size(&config, 100_000_000, 0));
1082        assert_eq!("  999,999,999", wrap_size(&config, 999_999_999, 0));
1083        assert_eq!("  1,000,000,000", wrap_size(&config, 1_000_000_000, 0));
1084        assert_eq!("  9,999,999,999", wrap_size(&config, 9_999_999_999, 0));
1085        assert_eq!("  10,000,000,000", wrap_size(&config, 10_000_000_000, 0));
1086        assert_eq!("  99,999,999,999", wrap_size(&config, 99_999_999_999, 0));
1087        assert_eq!("  100,000,000,000", wrap_size(&config, 100_000_000_000, 0));
1088        assert_eq!("  999,999,999,999", wrap_size(&config, 999_999_999_999, 0));
1089        assert_eq!("  1,000,000,000,000", wrap_size(&config, 1_000_000_000_000, 0));
1090        assert_eq!("  9,999,999,999,999", wrap_size(&config, 9_999_999_999_999, 0));
1091        assert_eq!("  10,000,000,000,000", wrap_size(&config, 10_000_000_000_000, 0));
1092        assert_eq!("  99,999,999,999,999", wrap_size(&config, 99_999_999_999_999, 0));
1093        assert_eq!("  100,000,000,000,000", wrap_size(&config, 100_000_000_000_000, 0));
1094        assert_eq!("  999,999,999,999,999", wrap_size(&config, 999_999_999_999_999, 0));
1095        assert_eq!("  1,000,000,000,000,000", wrap_size(&config, 1_000_000_000_000_000, 0));
1096        assert_eq!("  9,999,999,999,999,999", wrap_size(&config, 9_999_999_999_999_999, 0));
1097        assert_eq!("  10,000,000,000,000,000", wrap_size(&config, 10_000_000_000_000_000, 0));
1098        assert_eq!("  99,999,999,999,999,999", wrap_size(&config, 99_999_999_999_999_999, 0));
1099        assert_eq!("  100,000,000,000,000,000", wrap_size(&config, 100_000_000_000_000_000, 0));
1100        assert_eq!("  999,999,999,999,999,999", wrap_size(&config, 999_999_999_999_999_999, 0));
1101        assert_eq!("  1,000,000,000,000,000,000", wrap_size(&config, 1_000_000_000_000_000_000, 0));
1102        assert_eq!("  9,999,999,999,999,999,999", wrap_size(&config, 9_999_999_999_999_999_999, 0));
1103        assert_eq!("  10,000,000,000,000,000,000", wrap_size(&config, 10_000_000_000_000_000_000, 0));
1104    }
1105
1106    #[test]
1107    fn test_prints_padded_size_as_integer() {
1108        let config = Config::default()
1109            .with_show_precise(true);
1110        assert_eq!("                           0", wrap_size(&config, 0, 26));
1111        assert_eq!("                           9", wrap_size(&config, 9, 26));
1112        assert_eq!("                          10", wrap_size(&config, 10, 26));
1113        assert_eq!("                          99", wrap_size(&config, 99, 26));
1114        assert_eq!("                         100", wrap_size(&config, 100, 26));
1115        assert_eq!("                         999", wrap_size(&config, 999, 26));
1116        assert_eq!("                       1,000", wrap_size(&config, 1_000, 26));
1117        assert_eq!("                       9,999", wrap_size(&config, 9_999, 26));
1118        assert_eq!("                      10,000", wrap_size(&config, 10_000, 26));
1119        assert_eq!("                      99,999", wrap_size(&config, 99_999, 26));
1120        assert_eq!("                     100,000", wrap_size(&config, 100_000, 26));
1121        assert_eq!("                     999,999", wrap_size(&config, 999_999, 26));
1122        assert_eq!("                   1,000,000", wrap_size(&config, 1_000_000, 26));
1123        assert_eq!("                   9,999,999", wrap_size(&config, 9_999_999, 26));
1124        assert_eq!("                  10,000,000", wrap_size(&config, 10_000_000, 26));
1125        assert_eq!("                  99,999,999", wrap_size(&config, 99_999_999, 26));
1126        assert_eq!("                 100,000,000", wrap_size(&config, 100_000_000, 26));
1127        assert_eq!("                 999,999,999", wrap_size(&config, 999_999_999, 26));
1128        assert_eq!("               1,000,000,000", wrap_size(&config, 1_000_000_000, 26));
1129        assert_eq!("               9,999,999,999", wrap_size(&config, 9_999_999_999, 26));
1130        assert_eq!("              10,000,000,000", wrap_size(&config, 10_000_000_000, 26));
1131        assert_eq!("              99,999,999,999", wrap_size(&config, 99_999_999_999, 26));
1132        assert_eq!("             100,000,000,000", wrap_size(&config, 100_000_000_000, 26));
1133        assert_eq!("             999,999,999,999", wrap_size(&config, 999_999_999_999, 26));
1134        assert_eq!("           1,000,000,000,000", wrap_size(&config, 1_000_000_000_000, 26));
1135        assert_eq!("           9,999,999,999,999", wrap_size(&config, 9_999_999_999_999, 26));
1136        assert_eq!("          10,000,000,000,000", wrap_size(&config, 10_000_000_000_000, 26));
1137        assert_eq!("          99,999,999,999,999", wrap_size(&config, 99_999_999_999_999, 26));
1138        assert_eq!("         100,000,000,000,000", wrap_size(&config, 100_000_000_000_000, 26));
1139        assert_eq!("         999,999,999,999,999", wrap_size(&config, 999_999_999_999_999, 26));
1140        assert_eq!("       1,000,000,000,000,000", wrap_size(&config, 1_000_000_000_000_000, 26));
1141        assert_eq!("       9,999,999,999,999,999", wrap_size(&config, 9_999_999_999_999_999, 26));
1142        assert_eq!("      10,000,000,000,000,000", wrap_size(&config, 10_000_000_000_000_000, 26));
1143        assert_eq!("      99,999,999,999,999,999", wrap_size(&config, 99_999_999_999_999_999, 26));
1144        assert_eq!("     100,000,000,000,000,000", wrap_size(&config, 100_000_000_000_000_000, 26));
1145        assert_eq!("     999,999,999,999,999,999", wrap_size(&config, 999_999_999_999_999_999, 26));
1146        assert_eq!("   1,000,000,000,000,000,000", wrap_size(&config, 1_000_000_000_000_000_000, 26));
1147        assert_eq!("   9,999,999,999,999,999,999", wrap_size(&config, 9_999_999_999_999_999_999, 26));
1148        assert_eq!("  10,000,000,000,000,000,000", wrap_size(&config, 10_000_000_000_000_000_000, 26));
1149    }
1150
1151    #[test]
1152    fn test_prints_unpadded_size_in_si_units() {
1153        let config = Config::default()
1154            .with_show_precise(false);
1155        assert_eq!("    0 B ", wrap_size(&config, 0, 0));
1156        assert_eq!("    9 B ", wrap_size(&config, 9, 0));
1157        assert_eq!("   10 B ", wrap_size(&config, 10, 0));
1158        assert_eq!("   99 B ", wrap_size(&config, 99, 0));
1159        assert_eq!("  100 B ", wrap_size(&config, 100, 0));
1160        assert_eq!("  999 B ", wrap_size(&config, 999, 0));
1161        assert_eq!("    1 KB", wrap_size(&config, 1_000, 0));
1162        assert_eq!("    9 KB", wrap_size(&config, 9_999, 0));
1163        assert_eq!("   10 KB", wrap_size(&config, 10_000, 0));
1164        assert_eq!("   99 KB", wrap_size(&config, 99_999, 0));
1165        assert_eq!("  100 KB", wrap_size(&config, 100_000, 0));
1166        assert_eq!("  999 KB", wrap_size(&config, 999_999, 0));
1167        assert_eq!("    1 MB", wrap_size(&config, 1_000_000, 0));
1168        assert_eq!("    9 MB", wrap_size(&config, 9_999_999, 0));
1169        assert_eq!("   10 MB", wrap_size(&config, 10_000_000, 0));
1170        assert_eq!("   99 MB", wrap_size(&config, 99_999_999, 0));
1171        assert_eq!("  100 MB", wrap_size(&config, 100_000_000, 0));
1172        assert_eq!("  999 MB", wrap_size(&config, 999_999_999, 0));
1173        assert_eq!("    1 GB", wrap_size(&config, 1_000_000_000, 0));
1174        assert_eq!("    9 GB", wrap_size(&config, 9_999_999_999, 0));
1175        assert_eq!("   10 GB", wrap_size(&config, 10_000_000_000, 0));
1176        assert_eq!("   99 GB", wrap_size(&config, 99_999_999_999, 0));
1177        assert_eq!("  100 GB", wrap_size(&config, 100_000_000_000, 0));
1178        assert_eq!("  999 GB", wrap_size(&config, 999_999_999_999, 0));
1179        assert_eq!("    1 TB", wrap_size(&config, 1_000_000_000_000, 0));
1180        assert_eq!("    9 TB", wrap_size(&config, 9_999_999_999_999, 0));
1181        assert_eq!("   10 TB", wrap_size(&config, 10_000_000_000_000, 0));
1182        assert_eq!("   99 TB", wrap_size(&config, 99_999_999_999_999, 0));
1183        assert_eq!("  100 TB", wrap_size(&config, 100_000_000_000_000, 0));
1184        assert_eq!("  999 TB", wrap_size(&config, 999_999_999_999_999, 0));
1185        assert_eq!("    1 PB", wrap_size(&config, 1_000_000_000_000_000, 0));
1186        assert_eq!("    9 PB", wrap_size(&config, 9_999_999_999_999_999, 0));
1187        assert_eq!("   10 PB", wrap_size(&config, 10_000_000_000_000_000, 0));
1188        assert_eq!("   99 PB", wrap_size(&config, 99_999_999_999_999_999, 0));
1189        assert_eq!("  100 PB", wrap_size(&config, 100_000_000_000_000_000, 0));
1190        assert_eq!("  999 PB", wrap_size(&config, 999_999_999_999_999_999, 0));
1191        assert_eq!("    1 EB", wrap_size(&config, 1_000_000_000_000_000_000, 0));
1192        assert_eq!("    9 EB", wrap_size(&config, 9_999_999_999_999_999_999, 0));
1193        assert_eq!("   10 EB", wrap_size(&config, 10_000_000_000_000_000_000, 0));
1194    }
1195
1196    #[test]
1197    fn test_prints_time_as_local_timestamp() {
1198        let config = Config::default()
1199            .with_curr_time(2024, 10, 10, 10, 10, 30)
1200            .with_show_precise(true)
1201            .with_show_utc(false);
1202        assert_eq!("  Wed 31-Jan-2024 00:00:00", wrap_time(&config, 2024, 1, 31, 0, 0, 0));
1203        assert_eq!("  Thu 29-Feb-2024 02:05:15", wrap_time(&config, 2024, 2, 29, 2, 5, 15));
1204        assert_eq!("  Sun 31-Mar-2024 04:10:30", wrap_time(&config, 2024, 3, 31, 4, 10, 30));
1205        assert_eq!("  Tue 30-Apr-2024 06:15:45", wrap_time(&config, 2024, 4, 30, 6, 15, 45));
1206        assert_eq!("  Fri 31-May-2024 08:20:00", wrap_time(&config, 2024, 5, 31, 8, 20, 0));
1207        assert_eq!("  Sun 30-Jun-2024 10:25:15", wrap_time(&config, 2024, 6, 30, 10, 25, 15));
1208        assert_eq!("  Wed 31-Jul-2024 12:30:30", wrap_time(&config, 2024, 7, 31, 12, 30, 30));
1209        assert_eq!("  Sat 31-Aug-2024 14:35:45", wrap_time(&config, 2024, 8, 31, 14, 35, 45));
1210        assert_eq!("  Mon 30-Sep-2024 16:40:00", wrap_time(&config, 2024, 9, 30, 16, 40, 0));
1211        assert_eq!("  Thu 31-Oct-2024 18:45:15", wrap_time(&config, 2024, 10, 31, 18, 45, 15));
1212        assert_eq!("  Sat 30-Nov-2024 20:50:30", wrap_time(&config, 2024, 11, 30, 20, 50, 30));
1213        assert_eq!("  Tue 31-Dec-2024 22:55:45", wrap_time(&config, 2024, 12, 31, 22, 55, 45));
1214        assert_eq!("  ------------------------", wrap_time(&config, 1970, 1, 1, 0, 0, 0));
1215    }
1216
1217    #[test]
1218    fn test_prints_time_as_utc_timestamp() {
1219        let config = Config::default()
1220            .with_curr_time(2024, 10, 10, 10, 10, 30)
1221            .with_show_precise(true)
1222            .with_show_utc(true);
1223        assert_eq!("  Wed 31-Jan-2024 00:00:00Z", wrap_time(&config, 2024, 1, 31, 0, 0, 0));
1224        assert_eq!("  Thu 29-Feb-2024 02:05:15Z", wrap_time(&config, 2024, 2, 29, 2, 5, 15));
1225        assert_eq!("  Sun 31-Mar-2024 04:10:30Z", wrap_time(&config, 2024, 3, 31, 4, 10, 30));
1226        assert_eq!("  Tue 30-Apr-2024 06:15:45Z", wrap_time(&config, 2024, 4, 30, 6, 15, 45));
1227        assert_eq!("  Fri 31-May-2024 08:20:00Z", wrap_time(&config, 2024, 5, 31, 8, 20, 0));
1228        assert_eq!("  Sun 30-Jun-2024 10:25:15Z", wrap_time(&config, 2024, 6, 30, 10, 25, 15));
1229        assert_eq!("  Wed 31-Jul-2024 12:30:30Z", wrap_time(&config, 2024, 7, 31, 12, 30, 30));
1230        assert_eq!("  Sat 31-Aug-2024 14:35:45Z", wrap_time(&config, 2024, 8, 31, 14, 35, 45));
1231        assert_eq!("  Mon 30-Sep-2024 16:40:00Z", wrap_time(&config, 2024, 9, 30, 16, 40, 0));
1232        assert_eq!("  Thu 31-Oct-2024 18:45:15Z", wrap_time(&config, 2024, 10, 31, 18, 45, 15));
1233        assert_eq!("  Sat 30-Nov-2024 20:50:30Z", wrap_time(&config, 2024, 11, 30, 20, 50, 30));
1234        assert_eq!("  Tue 31-Dec-2024 22:55:45Z", wrap_time(&config, 2024, 12, 31, 22, 55, 45));
1235        assert_eq!("  -------------------------", wrap_time(&config, 1970, 1, 1, 0, 0, 0));
1236    }
1237
1238    #[test]
1239    fn test_prints_time_as_duration() {
1240        let config = Config::default()
1241            .with_curr_time(2024, 10, 10, 10, 10, 30)
1242            .with_show_precise(false);
1243        assert_eq!("   future ", wrap_time(&config, 2024, 10, 10, 10, 10, 31));
1244        assert_eq!("   0 sec  ", wrap_time(&config, 2024, 10, 10, 10, 10, 30));
1245        assert_eq!("   1 sec  ", wrap_time(&config, 2024, 10, 10, 10, 10, 29));
1246        assert_eq!("  59 sec  ", wrap_time(&config, 2024, 10, 10, 10, 9, 31));
1247        assert_eq!("   1 min  ", wrap_time(&config, 2024, 10, 10, 10, 9, 30));
1248        assert_eq!("   1 min  ", wrap_time(&config, 2024, 10, 10, 10, 9, 29));
1249        assert_eq!("   1 min  ", wrap_time(&config, 2024, 10, 10, 10, 8, 31));
1250        assert_eq!("   2 min  ", wrap_time(&config, 2024, 10, 10, 10, 8, 30));
1251        assert_eq!("   2 min  ", wrap_time(&config, 2024, 10, 10, 10, 8, 29));
1252        assert_eq!("  58 min  ", wrap_time(&config, 2024, 10, 10, 9, 11, 31));
1253        assert_eq!("  59 min  ", wrap_time(&config, 2024, 10, 10, 9, 11, 30));
1254        assert_eq!("  59 min  ", wrap_time(&config, 2024, 10, 10, 9, 11, 29));
1255        assert_eq!("  59 min  ", wrap_time(&config, 2024, 10, 10, 9, 10, 31));
1256        assert_eq!("   1 hour ", wrap_time(&config, 2024, 10, 10, 9, 10, 30));
1257        assert_eq!("   1 hour ", wrap_time(&config, 2024, 10, 10, 9, 10, 29));
1258        assert_eq!("   1 hour ", wrap_time(&config, 2024, 10, 10, 8, 10, 31));
1259        assert_eq!("   2 hour ", wrap_time(&config, 2024, 10, 10, 8, 10, 30));
1260        assert_eq!("   2 hour ", wrap_time(&config, 2024, 10, 10, 8, 10, 29));
1261        assert_eq!("  22 hour ", wrap_time(&config, 2024, 10, 9, 11, 10, 31));
1262        assert_eq!("  23 hour ", wrap_time(&config, 2024, 10, 9, 11, 10, 30));
1263        assert_eq!("  23 hour ", wrap_time(&config, 2024, 10, 9, 11, 10, 29));
1264        assert_eq!("  23 hour ", wrap_time(&config, 2024, 10, 9, 10, 10, 31));
1265        assert_eq!("   1 day  ", wrap_time(&config, 2024, 10, 9, 10, 10, 30));
1266        assert_eq!("   1 day  ", wrap_time(&config, 2024, 10, 9, 10, 10, 29));
1267        assert_eq!("   1 day  ", wrap_time(&config, 2024, 10, 8, 10, 10, 31));
1268        assert_eq!("   2 day  ", wrap_time(&config, 2024, 10, 8, 10, 10, 30));
1269        assert_eq!("   2 day  ", wrap_time(&config, 2024, 10, 8, 10, 10, 29));
1270        assert_eq!("  28 day  ", wrap_time(&config, 2024, 9, 11, 10, 10, 31));
1271        assert_eq!("  29 day  ", wrap_time(&config, 2024, 9, 11, 10, 10, 30));
1272        assert_eq!("  29 day  ", wrap_time(&config, 2024, 9, 11, 10, 10, 29));
1273        assert_eq!("  29 day  ", wrap_time(&config, 2024, 9, 10, 10, 10, 31));
1274        assert_eq!("   1 month", wrap_time(&config, 2024, 9, 10, 10, 10, 30));
1275        assert_eq!("   1 month", wrap_time(&config, 2024, 9, 10, 10, 10, 29));
1276        assert_eq!("   1 month", wrap_time(&config, 2024, 8, 10, 10, 10, 31));
1277        assert_eq!("   2 month", wrap_time(&config, 2024, 8, 10, 10, 10, 30));
1278        assert_eq!("   2 month", wrap_time(&config, 2024, 8, 10, 10, 10, 29));
1279        assert_eq!("  10 month", wrap_time(&config, 2023, 11, 10, 10, 10, 31));
1280        assert_eq!("  11 month", wrap_time(&config, 2023, 11, 10, 10, 10, 30));
1281        assert_eq!("  11 month", wrap_time(&config, 2023, 11, 10, 10, 10, 29));
1282        assert_eq!("  11 month", wrap_time(&config, 2023, 10, 10, 10, 10, 31));
1283        assert_eq!("   1 year ", wrap_time(&config, 2023, 10, 10, 10, 10, 30));
1284        assert_eq!("   1 year ", wrap_time(&config, 2023, 10, 10, 10, 10, 29));
1285        assert_eq!("   1 year ", wrap_time(&config, 2022, 10, 10, 10, 10, 31));
1286        assert_eq!("   2 year ", wrap_time(&config, 2022, 10, 10, 10, 10, 30));
1287        assert_eq!("   2 year ", wrap_time(&config, 2022, 10, 10, 10, 10, 29));
1288        assert_eq!("  --------", wrap_time(&config, 1970, 1, 1, 0, 0, 0));
1289    }
1290
1291    #[test]
1292    #[cfg(windows)]
1293    fn test_prints_unpadded_version() {
1294        assert_eq!("", wrap_version(None, 0));
1295        assert_eq!("", wrap_version(Some(""), 0));
1296        assert_eq!("", wrap_version(Some("9.9.9.9"), 0));
1297        assert_eq!("", wrap_version(Some("999.999.999.999"), 0));
1298    }
1299
1300    #[test]
1301    #[cfg(windows)]
1302    fn test_prints_padded_version() {
1303        assert_eq!("            ", wrap_version(None, 10));
1304        assert_eq!("            ", wrap_version(Some(""), 10));
1305        assert_eq!("  9.9.9.9   ", wrap_version(Some("9.9.9.9"), 10));
1306        assert_eq!("  999.999.999.999", wrap_version(Some("999.999.999.999"), 10));
1307    }
1308
1309    #[test]
1310    fn test_prints_unpadded_ext() {
1311        assert_eq!("", wrap_ext("", 0));
1312        assert_eq!("", wrap_ext(".txt", 0));
1313        assert_eq!("", wrap_ext(".extension", 0));
1314    }
1315
1316    #[test]
1317    fn test_prints_padded_ext() {
1318        assert_eq!("        ", wrap_ext("", 6));
1319        assert_eq!("  .txt  ", wrap_ext(".txt", 6));
1320        assert_eq!("  .extension", wrap_ext(".extension", 6));
1321    }
1322
1323    #[test]
1324    fn test_prints_total() {
1325        assert_eq!("0 files 0 directories", wrap_total(0, 0));
1326        assert_eq!("1 file 0 directories", wrap_total(1, 0));
1327        assert_eq!("2 files 0 directories", wrap_total(2, 0));
1328        assert_eq!("0 files 1 directory", wrap_total(0, 1));
1329        assert_eq!("0 files 2 directories", wrap_total(0, 2));
1330    }
1331
1332    #[test]
1333    #[cfg(windows)]
1334    fn test_prints_relative_paths_on_windows() {
1335        let expected = "\
1336drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example\\[Reset]
1337-rwxr-xr-x   10  Wed 01-Nov-2023 00:00:00  .sh   [LtBlue]example\\[Reset][DkGreen]find.sh[Reset]
1338drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example\\files\\[Reset]
1339drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example\\files\\colours\\[Reset]
1340-rwxr--r--   20  Sun 01-Oct-2023 00:00:00  .sh   [LtBlue]example\\files\\colours\\[Reset][LtGreen]alpha.sh[Reset]
1341-rw-r--r--   30  Fri 01-Sep-2023 00:00:00  .txt  [LtBlue]example\\files\\colours\\[Reset]blue.txt
1342-rw-r--r--   40  Tue 01-Aug-2023 00:00:00  .txt  [LtBlue]example\\files\\colours\\[Reset]green.txt
1343-rw-r--r--   50  Sat 01-Jul-2023 00:00:00  .txt  [LtBlue]example\\files\\colours\\[Reset]red.txt
1344drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example\\files\\numbers\\[Reset]
1345lrwxr--r--   60  Thu 01-Jun-2023 00:00:00  .sh   [LtBlue]example\\files\\numbers\\[Reset][LtCyan]count.sh[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtGreen]count.sh[Reset]
1346lrw-r--r--  999  Mon 01-May-2023 00:00:00  .gz   [LtBlue]example\\files\\numbers\\[Reset][LtCyan]googolplex.gz[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtRed]googolplex.gz[Reset]
1347lrw-r--r--    0  Sat 01-Apr-2023 00:00:00        [LtBlue]example\\files\\numbers\\[Reset][LtCyan]ordinals[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtBlue]ordinals\\[Reset]
1348drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example\\files\\numbers\\one two\\[Reset]
1349-rw-r--r--   70  Wed 01-Mar-2023 00:00:00  .txt  [LtBlue]example\\files\\numbers\\one two\\[Reset]\"three\" 'four'.txt
1350";
1351        let files = create_files("D:", "/root", "");
1352        let config = Config::default()
1353            .with_show_precise(true)
1354            .with_abs_path(false);
1355        assert_eq!(expected, wrap_files(&config, false, &files));
1356    }
1357
1358    #[test]
1359    #[cfg(windows)]
1360    fn test_prints_relative_paths_on_git_bash() {
1361        let expected = "\
1362drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/[Reset]
1363-rwxr-xr-x   10  Wed 01-Nov-2023 00:00:00  .sh   [LtBlue]example/[Reset][DkGreen]find.sh[Reset]
1364drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/files/[Reset]
1365drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/files/colours/[Reset]
1366-rwxr--r--   20  Sun 01-Oct-2023 00:00:00  .sh   [LtBlue]example/files/colours/[Reset][LtGreen]alpha.sh[Reset]
1367-rw-r--r--   30  Fri 01-Sep-2023 00:00:00  .txt  [LtBlue]example/files/colours/[Reset]blue.txt
1368-rw-r--r--   40  Tue 01-Aug-2023 00:00:00  .txt  [LtBlue]example/files/colours/[Reset]green.txt
1369-rw-r--r--   50  Sat 01-Jul-2023 00:00:00  .txt  [LtBlue]example/files/colours/[Reset]red.txt
1370drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/files/numbers/[Reset]
1371lrwxr--r--   60  Thu 01-Jun-2023 00:00:00  .sh   [LtBlue]example/files/numbers/[Reset][LtCyan]count.sh[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtGreen]count.sh[Reset]
1372lrw-r--r--  999  Mon 01-May-2023 00:00:00  .gz   [LtBlue]example/files/numbers/[Reset][LtCyan]googolplex.gz[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtRed]googolplex.gz[Reset]
1373lrw-r--r--    0  Sat 01-Apr-2023 00:00:00        [LtBlue]example/files/numbers/[Reset][LtCyan]ordinals[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtBlue]ordinals/[Reset]
1374drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/files/numbers/one two/[Reset]
1375-rw-r--r--   70  Wed 01-Mar-2023 00:00:00  .txt  [LtBlue]example/files/numbers/one two/[Reset]\"three\" 'four'.txt
1376";
1377        let files = create_files("D:", "/root", "");
1378        let config = Config::default()
1379            .with_show_precise(true)
1380            .with_abs_path(false);
1381        assert_eq!(expected, wrap_files(&config, true, &files));
1382    }
1383
1384    #[test]
1385    #[cfg(not(windows))]
1386    fn test_prints_relative_paths_on_linux() {
1387        let expected = "\
1388drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/[Reset]
1389-rwxr-xr-x   10  Wed 01-Nov-2023 00:00:00  .sh   [LtBlue]example/[Reset][DkGreen]find.sh[Reset]
1390drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/files/[Reset]
1391drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/files/colours/[Reset]
1392-rwxr--r--   20  Sun 01-Oct-2023 00:00:00  .sh   [LtBlue]example/files/colours/[Reset][LtGreen]alpha.sh[Reset]
1393-rw-r--r--   30  Fri 01-Sep-2023 00:00:00  .txt  [LtBlue]example/files/colours/[Reset]blue.txt
1394-rw-r--r--   40  Tue 01-Aug-2023 00:00:00  .txt  [LtBlue]example/files/colours/[Reset]green.txt
1395-rw-r--r--   50  Sat 01-Jul-2023 00:00:00  .txt  [LtBlue]example/files/colours/[Reset]red.txt
1396drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/files/numbers/[Reset]
1397lrwxr--r--   60  Thu 01-Jun-2023 00:00:00  .sh   [LtBlue]example/files/numbers/[Reset][LtCyan]count.sh[Reset] -> [LtBlue]/etc/numbers/[Reset][LtGreen]count.sh[Reset]
1398lrw-r--r--  999  Mon 01-May-2023 00:00:00  .gz   [LtBlue]example/files/numbers/[Reset][LtCyan]googolplex.gz[Reset] -> [LtBlue]/etc/numbers/[Reset][LtRed]googolplex.gz[Reset]
1399lrw-r--r--    0  Sat 01-Apr-2023 00:00:00        [LtBlue]example/files/numbers/[Reset][LtCyan]ordinals[Reset] -> [LtBlue]/etc/numbers/[Reset][LtBlue]ordinals/[Reset]
1400drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/files/numbers/one two/[Reset]
1401-rw-r--r--   70  Wed 01-Mar-2023 00:00:00  .txt  [LtBlue]example/files/numbers/one two/[Reset]\"three\" 'four'.txt
1402";
1403        let files = create_files("", "/root", "");
1404        let config = Config::default()
1405            .with_show_precise(true)
1406            .with_abs_path(false);
1407        assert_eq!(expected, wrap_files(&config, false, &files));
1408    }
1409
1410    #[test]
1411    #[cfg(windows)]
1412    fn test_prints_absolute_paths_on_windows() {
1413        let expected = "\
1414drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]D:\\root\\example\\[Reset]
1415-rwxr-xr-x   10  Wed 01-Nov-2023 00:00:00  .sh   [LtBlue]D:\\root\\example\\[Reset][DkGreen]find.sh[Reset]
1416drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]D:\\root\\example\\files\\[Reset]
1417drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]D:\\root\\example\\files\\colours\\[Reset]
1418-rwxr--r--   20  Sun 01-Oct-2023 00:00:00  .sh   [LtBlue]D:\\root\\example\\files\\colours\\[Reset][LtGreen]alpha.sh[Reset]
1419-rw-r--r--   30  Fri 01-Sep-2023 00:00:00  .txt  [LtBlue]D:\\root\\example\\files\\colours\\[Reset]blue.txt
1420-rw-r--r--   40  Tue 01-Aug-2023 00:00:00  .txt  [LtBlue]D:\\root\\example\\files\\colours\\[Reset]green.txt
1421-rw-r--r--   50  Sat 01-Jul-2023 00:00:00  .txt  [LtBlue]D:\\root\\example\\files\\colours\\[Reset]red.txt
1422drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]D:\\root\\example\\files\\numbers\\[Reset]
1423lrwxr--r--   60  Thu 01-Jun-2023 00:00:00  .sh   [LtBlue]D:\\root\\example\\files\\numbers\\[Reset][LtCyan]count.sh[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtGreen]count.sh[Reset]
1424lrw-r--r--  999  Mon 01-May-2023 00:00:00  .gz   [LtBlue]D:\\root\\example\\files\\numbers\\[Reset][LtCyan]googolplex.gz[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtRed]googolplex.gz[Reset]
1425lrw-r--r--    0  Sat 01-Apr-2023 00:00:00        [LtBlue]D:\\root\\example\\files\\numbers\\[Reset][LtCyan]ordinals[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtBlue]ordinals\\[Reset]
1426drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]D:\\root\\example\\files\\numbers\\one two\\[Reset]
1427-rw-r--r--   70  Wed 01-Mar-2023 00:00:00  .txt  [LtBlue]D:\\root\\example\\files\\numbers\\one two\\[Reset]\"three\" 'four'.txt
1428";
1429        let files = create_files("D:", "/root", "");
1430        let config = Config::default()
1431            .with_show_precise(true)
1432            .with_abs_path(true);
1433        assert_eq!(expected, wrap_files(&config, false, &files));
1434    }
1435
1436    #[test]
1437    #[cfg(windows)]
1438    fn test_prints_absolute_paths_on_git_bash() {
1439        let expected = "\
1440drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]/d/root/example/[Reset]
1441-rwxr-xr-x   10  Wed 01-Nov-2023 00:00:00  .sh   [LtBlue]/d/root/example/[Reset][DkGreen]find.sh[Reset]
1442drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]/d/root/example/files/[Reset]
1443drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]/d/root/example/files/colours/[Reset]
1444-rwxr--r--   20  Sun 01-Oct-2023 00:00:00  .sh   [LtBlue]/d/root/example/files/colours/[Reset][LtGreen]alpha.sh[Reset]
1445-rw-r--r--   30  Fri 01-Sep-2023 00:00:00  .txt  [LtBlue]/d/root/example/files/colours/[Reset]blue.txt
1446-rw-r--r--   40  Tue 01-Aug-2023 00:00:00  .txt  [LtBlue]/d/root/example/files/colours/[Reset]green.txt
1447-rw-r--r--   50  Sat 01-Jul-2023 00:00:00  .txt  [LtBlue]/d/root/example/files/colours/[Reset]red.txt
1448drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]/d/root/example/files/numbers/[Reset]
1449lrwxr--r--   60  Thu 01-Jun-2023 00:00:00  .sh   [LtBlue]/d/root/example/files/numbers/[Reset][LtCyan]count.sh[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtGreen]count.sh[Reset]
1450lrw-r--r--  999  Mon 01-May-2023 00:00:00  .gz   [LtBlue]/d/root/example/files/numbers/[Reset][LtCyan]googolplex.gz[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtRed]googolplex.gz[Reset]
1451lrw-r--r--    0  Sat 01-Apr-2023 00:00:00        [LtBlue]/d/root/example/files/numbers/[Reset][LtCyan]ordinals[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtBlue]ordinals/[Reset]
1452drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]/d/root/example/files/numbers/one two/[Reset]
1453-rw-r--r--   70  Wed 01-Mar-2023 00:00:00  .txt  [LtBlue]/d/root/example/files/numbers/one two/[Reset]\"three\" 'four'.txt
1454";
1455        let files = create_files("D:", "/root", "");
1456        let config = Config::default()
1457            .with_show_precise(true)
1458            .with_abs_path(true);
1459        assert_eq!(expected, wrap_files(&config, true, &files));
1460    }
1461
1462    #[test]
1463    #[cfg(not(windows))]
1464    fn test_prints_absolute_paths_on_linux() {
1465        let expected = "\
1466drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]/root/example/[Reset]
1467-rwxr-xr-x   10  Wed 01-Nov-2023 00:00:00  .sh   [LtBlue]/root/example/[Reset][DkGreen]find.sh[Reset]
1468drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]/root/example/files/[Reset]
1469drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]/root/example/files/colours/[Reset]
1470-rwxr--r--   20  Sun 01-Oct-2023 00:00:00  .sh   [LtBlue]/root/example/files/colours/[Reset][LtGreen]alpha.sh[Reset]
1471-rw-r--r--   30  Fri 01-Sep-2023 00:00:00  .txt  [LtBlue]/root/example/files/colours/[Reset]blue.txt
1472-rw-r--r--   40  Tue 01-Aug-2023 00:00:00  .txt  [LtBlue]/root/example/files/colours/[Reset]green.txt
1473-rw-r--r--   50  Sat 01-Jul-2023 00:00:00  .txt  [LtBlue]/root/example/files/colours/[Reset]red.txt
1474drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]/root/example/files/numbers/[Reset]
1475lrwxr--r--   60  Thu 01-Jun-2023 00:00:00  .sh   [LtBlue]/root/example/files/numbers/[Reset][LtCyan]count.sh[Reset] -> [LtBlue]/etc/numbers/[Reset][LtGreen]count.sh[Reset]
1476lrw-r--r--  999  Mon 01-May-2023 00:00:00  .gz   [LtBlue]/root/example/files/numbers/[Reset][LtCyan]googolplex.gz[Reset] -> [LtBlue]/etc/numbers/[Reset][LtRed]googolplex.gz[Reset]
1477lrw-r--r--    0  Sat 01-Apr-2023 00:00:00        [LtBlue]/root/example/files/numbers/[Reset][LtCyan]ordinals[Reset] -> [LtBlue]/etc/numbers/[Reset][LtBlue]ordinals/[Reset]
1478drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]/root/example/files/numbers/one two/[Reset]
1479-rw-r--r--   70  Wed 01-Mar-2023 00:00:00  .txt  [LtBlue]/root/example/files/numbers/one two/[Reset]\"three\" 'four'.txt
1480";
1481        let files = create_files("", "/root", "");
1482        let config = Config::default()
1483            .with_show_precise(true)
1484            .with_abs_path(true);
1485        assert_eq!(expected, wrap_files(&config, false, &files));
1486    }
1487
1488    #[test]
1489    #[cfg(windows)]
1490    fn test_prints_relative_paths_with_zip_on_windows() {
1491        let expected = "\
1492-drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example\\[Reset]
1493--rwxr-xr-x   10  Wed 01-Nov-2023 00:00:00  .sh   [LtBlue]example\\[Reset][DkGreen]find.sh[Reset]
1494zdrwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example\\[LtRed]files.zip[LtBlue]\\[Reset]
1495zdrwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example\\[LtRed]files.zip[LtBlue]\\colours\\[Reset]
1496z-rwxr--r--   20  Sun 01-Oct-2023 00:00:00  .sh   [LtBlue]example\\[LtRed]files.zip[LtBlue]\\colours\\[Reset][LtGreen]alpha.sh[Reset]
1497z-rw-r--r--   30  Fri 01-Sep-2023 00:00:00  .txt  [LtBlue]example\\[LtRed]files.zip[LtBlue]\\colours\\[Reset]blue.txt
1498z-rw-r--r--   40  Tue 01-Aug-2023 00:00:00  .txt  [LtBlue]example\\[LtRed]files.zip[LtBlue]\\colours\\[Reset]green.txt
1499z-rw-r--r--   50  Sat 01-Jul-2023 00:00:00  .txt  [LtBlue]example\\[LtRed]files.zip[LtBlue]\\colours\\[Reset]red.txt
1500zdrwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example\\[LtRed]files.zip[LtBlue]\\numbers\\[Reset]
1501zlrwxr--r--   60  Thu 01-Jun-2023 00:00:00  .sh   [LtBlue]example\\[LtRed]files.zip[LtBlue]\\numbers\\[Reset][LtCyan]count.sh[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtGreen]count.sh[Reset]
1502zlrw-r--r--  999  Mon 01-May-2023 00:00:00  .gz   [LtBlue]example\\[LtRed]files.zip[LtBlue]\\numbers\\[Reset][LtCyan]googolplex.gz[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtRed]googolplex.gz[Reset]
1503zlrw-r--r--    0  Sat 01-Apr-2023 00:00:00        [LtBlue]example\\[LtRed]files.zip[LtBlue]\\numbers\\[Reset][LtCyan]ordinals[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtBlue]ordinals\\[Reset]
1504zdrwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example\\[LtRed]files.zip[LtBlue]\\numbers\\one two\\[Reset]
1505z-rw-r--r--   70  Wed 01-Mar-2023 00:00:00  .txt  [LtBlue]example\\[LtRed]files.zip[LtBlue]\\numbers\\one two\\[Reset]\"three\" 'four'.txt
1506";
1507        let files = create_files("D:", "/root", "");
1508        let files = modify_files_for_zip(files);
1509        let config = Config::default()
1510            .with_zip_expand(true)
1511            .with_show_precise(true)
1512            .with_abs_path(false);
1513        assert_eq!(expected, wrap_files(&config, false, &files));
1514    }
1515
1516    #[test]
1517    #[cfg(windows)]
1518    fn test_prints_relative_paths_with_zip_on_git_bash() {
1519        let expected = "\
1520-drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/[Reset]
1521--rwxr-xr-x   10  Wed 01-Nov-2023 00:00:00  .sh   [LtBlue]example/[Reset][DkGreen]find.sh[Reset]
1522zdrwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/[LtRed]files.zip[LtBlue]/[Reset]
1523zdrwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/[LtRed]files.zip[LtBlue]/colours/[Reset]
1524z-rwxr--r--   20  Sun 01-Oct-2023 00:00:00  .sh   [LtBlue]example/[LtRed]files.zip[LtBlue]/colours/[Reset][LtGreen]alpha.sh[Reset]
1525z-rw-r--r--   30  Fri 01-Sep-2023 00:00:00  .txt  [LtBlue]example/[LtRed]files.zip[LtBlue]/colours/[Reset]blue.txt
1526z-rw-r--r--   40  Tue 01-Aug-2023 00:00:00  .txt  [LtBlue]example/[LtRed]files.zip[LtBlue]/colours/[Reset]green.txt
1527z-rw-r--r--   50  Sat 01-Jul-2023 00:00:00  .txt  [LtBlue]example/[LtRed]files.zip[LtBlue]/colours/[Reset]red.txt
1528zdrwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/[LtRed]files.zip[LtBlue]/numbers/[Reset]
1529zlrwxr--r--   60  Thu 01-Jun-2023 00:00:00  .sh   [LtBlue]example/[LtRed]files.zip[LtBlue]/numbers/[Reset][LtCyan]count.sh[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtGreen]count.sh[Reset]
1530zlrw-r--r--  999  Mon 01-May-2023 00:00:00  .gz   [LtBlue]example/[LtRed]files.zip[LtBlue]/numbers/[Reset][LtCyan]googolplex.gz[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtRed]googolplex.gz[Reset]
1531zlrw-r--r--    0  Sat 01-Apr-2023 00:00:00        [LtBlue]example/[LtRed]files.zip[LtBlue]/numbers/[Reset][LtCyan]ordinals[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtBlue]ordinals/[Reset]
1532zdrwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/[LtRed]files.zip[LtBlue]/numbers/one two/[Reset]
1533z-rw-r--r--   70  Wed 01-Mar-2023 00:00:00  .txt  [LtBlue]example/[LtRed]files.zip[LtBlue]/numbers/one two/[Reset]\"three\" 'four'.txt
1534";
1535        let files = create_files("D:", "/root", "");
1536        let files = modify_files_for_zip(files);
1537        let config = Config::default()
1538            .with_zip_expand(true)
1539            .with_show_precise(true)
1540            .with_abs_path(false);
1541        assert_eq!(expected, wrap_files(&config, true, &files));
1542    }
1543
1544    #[test]
1545    #[cfg(not(windows))]
1546    fn test_prints_relative_paths_with_zip_on_linux() {
1547        let expected = "\
1548-drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/[Reset]
1549--rwxr-xr-x   10  Wed 01-Nov-2023 00:00:00  .sh   [LtBlue]example/[Reset][DkGreen]find.sh[Reset]
1550zdrwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/[LtRed]files.zip[LtBlue]/[Reset]
1551zdrwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/[LtRed]files.zip[LtBlue]/colours/[Reset]
1552z-rwxr--r--   20  Sun 01-Oct-2023 00:00:00  .sh   [LtBlue]example/[LtRed]files.zip[LtBlue]/colours/[Reset][LtGreen]alpha.sh[Reset]
1553z-rw-r--r--   30  Fri 01-Sep-2023 00:00:00  .txt  [LtBlue]example/[LtRed]files.zip[LtBlue]/colours/[Reset]blue.txt
1554z-rw-r--r--   40  Tue 01-Aug-2023 00:00:00  .txt  [LtBlue]example/[LtRed]files.zip[LtBlue]/colours/[Reset]green.txt
1555z-rw-r--r--   50  Sat 01-Jul-2023 00:00:00  .txt  [LtBlue]example/[LtRed]files.zip[LtBlue]/colours/[Reset]red.txt
1556zdrwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/[LtRed]files.zip[LtBlue]/numbers/[Reset]
1557zlrwxr--r--   60  Thu 01-Jun-2023 00:00:00  .sh   [LtBlue]example/[LtRed]files.zip[LtBlue]/numbers/[Reset][LtCyan]count.sh[Reset] -> [LtBlue]/etc/numbers/[Reset][LtGreen]count.sh[Reset]
1558zlrw-r--r--  999  Mon 01-May-2023 00:00:00  .gz   [LtBlue]example/[LtRed]files.zip[LtBlue]/numbers/[Reset][LtCyan]googolplex.gz[Reset] -> [LtBlue]/etc/numbers/[Reset][LtRed]googolplex.gz[Reset]
1559zlrw-r--r--    0  Sat 01-Apr-2023 00:00:00        [LtBlue]example/[LtRed]files.zip[LtBlue]/numbers/[Reset][LtCyan]ordinals[Reset] -> [LtBlue]/etc/numbers/[Reset][LtBlue]ordinals/[Reset]
1560zdrwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/[LtRed]files.zip[LtBlue]/numbers/one two/[Reset]
1561z-rw-r--r--   70  Wed 01-Mar-2023 00:00:00  .txt  [LtBlue]example/[LtRed]files.zip[LtBlue]/numbers/one two/[Reset]\"three\" 'four'.txt
1562";
1563        let files = create_files("", "/root", "");
1564        let files = modify_files_for_zip(files);
1565        let config = Config::default()
1566            .with_zip_expand(true)
1567            .with_show_precise(true)
1568            .with_abs_path(false);
1569        assert_eq!(expected, wrap_files(&config, false, &files));
1570    }
1571
1572    #[test]
1573    #[cfg(windows)]
1574    fn test_prints_absolute_paths_with_zip_on_windows() {
1575        let expected = "\
1576-drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]D:\\root\\example\\[Reset]
1577--rwxr-xr-x   10  Wed 01-Nov-2023 00:00:00  .sh   [LtBlue]D:\\root\\example\\[Reset][DkGreen]find.sh[Reset]
1578zdrwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]D:\\root\\example\\[LtRed]files.zip[LtBlue]\\[Reset]
1579zdrwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]D:\\root\\example\\[LtRed]files.zip[LtBlue]\\colours\\[Reset]
1580z-rwxr--r--   20  Sun 01-Oct-2023 00:00:00  .sh   [LtBlue]D:\\root\\example\\[LtRed]files.zip[LtBlue]\\colours\\[Reset][LtGreen]alpha.sh[Reset]
1581z-rw-r--r--   30  Fri 01-Sep-2023 00:00:00  .txt  [LtBlue]D:\\root\\example\\[LtRed]files.zip[LtBlue]\\colours\\[Reset]blue.txt
1582z-rw-r--r--   40  Tue 01-Aug-2023 00:00:00  .txt  [LtBlue]D:\\root\\example\\[LtRed]files.zip[LtBlue]\\colours\\[Reset]green.txt
1583z-rw-r--r--   50  Sat 01-Jul-2023 00:00:00  .txt  [LtBlue]D:\\root\\example\\[LtRed]files.zip[LtBlue]\\colours\\[Reset]red.txt
1584zdrwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]D:\\root\\example\\[LtRed]files.zip[LtBlue]\\numbers\\[Reset]
1585zlrwxr--r--   60  Thu 01-Jun-2023 00:00:00  .sh   [LtBlue]D:\\root\\example\\[LtRed]files.zip[LtBlue]\\numbers\\[Reset][LtCyan]count.sh[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtGreen]count.sh[Reset]
1586zlrw-r--r--  999  Mon 01-May-2023 00:00:00  .gz   [LtBlue]D:\\root\\example\\[LtRed]files.zip[LtBlue]\\numbers\\[Reset][LtCyan]googolplex.gz[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtRed]googolplex.gz[Reset]
1587zlrw-r--r--    0  Sat 01-Apr-2023 00:00:00        [LtBlue]D:\\root\\example\\[LtRed]files.zip[LtBlue]\\numbers\\[Reset][LtCyan]ordinals[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtBlue]ordinals\\[Reset]
1588zdrwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]D:\\root\\example\\[LtRed]files.zip[LtBlue]\\numbers\\one two\\[Reset]
1589z-rw-r--r--   70  Wed 01-Mar-2023 00:00:00  .txt  [LtBlue]D:\\root\\example\\[LtRed]files.zip[LtBlue]\\numbers\\one two\\[Reset]\"three\" 'four'.txt
1590";
1591        let files = create_files("D:", "/root", "");
1592        let files = modify_files_for_zip(files);
1593        let config = Config::default()
1594            .with_zip_expand(true)
1595            .with_show_precise(true)
1596            .with_abs_path(true);
1597        assert_eq!(expected, wrap_files(&config, false, &files));
1598    }
1599
1600    #[test]
1601    #[cfg(windows)]
1602    fn test_prints_absolute_paths_with_zip_on_git_bash() {
1603        let expected = "\
1604-drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]/d/root/example/[Reset]
1605--rwxr-xr-x   10  Wed 01-Nov-2023 00:00:00  .sh   [LtBlue]/d/root/example/[Reset][DkGreen]find.sh[Reset]
1606zdrwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]/d/root/example/[LtRed]files.zip[LtBlue]/[Reset]
1607zdrwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]/d/root/example/[LtRed]files.zip[LtBlue]/colours/[Reset]
1608z-rwxr--r--   20  Sun 01-Oct-2023 00:00:00  .sh   [LtBlue]/d/root/example/[LtRed]files.zip[LtBlue]/colours/[Reset][LtGreen]alpha.sh[Reset]
1609z-rw-r--r--   30  Fri 01-Sep-2023 00:00:00  .txt  [LtBlue]/d/root/example/[LtRed]files.zip[LtBlue]/colours/[Reset]blue.txt
1610z-rw-r--r--   40  Tue 01-Aug-2023 00:00:00  .txt  [LtBlue]/d/root/example/[LtRed]files.zip[LtBlue]/colours/[Reset]green.txt
1611z-rw-r--r--   50  Sat 01-Jul-2023 00:00:00  .txt  [LtBlue]/d/root/example/[LtRed]files.zip[LtBlue]/colours/[Reset]red.txt
1612zdrwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]/d/root/example/[LtRed]files.zip[LtBlue]/numbers/[Reset]
1613zlrwxr--r--   60  Thu 01-Jun-2023 00:00:00  .sh   [LtBlue]/d/root/example/[LtRed]files.zip[LtBlue]/numbers/[Reset][LtCyan]count.sh[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtGreen]count.sh[Reset]
1614zlrw-r--r--  999  Mon 01-May-2023 00:00:00  .gz   [LtBlue]/d/root/example/[LtRed]files.zip[LtBlue]/numbers/[Reset][LtCyan]googolplex.gz[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtRed]googolplex.gz[Reset]
1615zlrw-r--r--    0  Sat 01-Apr-2023 00:00:00        [LtBlue]/d/root/example/[LtRed]files.zip[LtBlue]/numbers/[Reset][LtCyan]ordinals[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtBlue]ordinals/[Reset]
1616zdrwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]/d/root/example/[LtRed]files.zip[LtBlue]/numbers/one two/[Reset]
1617z-rw-r--r--   70  Wed 01-Mar-2023 00:00:00  .txt  [LtBlue]/d/root/example/[LtRed]files.zip[LtBlue]/numbers/one two/[Reset]\"three\" 'four'.txt
1618";
1619        let files = create_files("D:", "/root", "");
1620        let files = modify_files_for_zip(files);
1621        let config = Config::default()
1622            .with_zip_expand(true)
1623            .with_show_precise(true)
1624            .with_abs_path(true);
1625        assert_eq!(expected, wrap_files(&config, true, &files));
1626    }
1627
1628    #[test]
1629    #[cfg(not(windows))]
1630    fn test_prints_absolute_paths_with_zip_on_linux() {
1631        let expected = "\
1632-drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]/root/example/[Reset]
1633--rwxr-xr-x   10  Wed 01-Nov-2023 00:00:00  .sh   [LtBlue]/root/example/[Reset][DkGreen]find.sh[Reset]
1634zdrwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]/root/example/[LtRed]files.zip[LtBlue]/[Reset]
1635zdrwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]/root/example/[LtRed]files.zip[LtBlue]/colours/[Reset]
1636z-rwxr--r--   20  Sun 01-Oct-2023 00:00:00  .sh   [LtBlue]/root/example/[LtRed]files.zip[LtBlue]/colours/[Reset][LtGreen]alpha.sh[Reset]
1637z-rw-r--r--   30  Fri 01-Sep-2023 00:00:00  .txt  [LtBlue]/root/example/[LtRed]files.zip[LtBlue]/colours/[Reset]blue.txt
1638z-rw-r--r--   40  Tue 01-Aug-2023 00:00:00  .txt  [LtBlue]/root/example/[LtRed]files.zip[LtBlue]/colours/[Reset]green.txt
1639z-rw-r--r--   50  Sat 01-Jul-2023 00:00:00  .txt  [LtBlue]/root/example/[LtRed]files.zip[LtBlue]/colours/[Reset]red.txt
1640zdrwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]/root/example/[LtRed]files.zip[LtBlue]/numbers/[Reset]
1641zlrwxr--r--   60  Thu 01-Jun-2023 00:00:00  .sh   [LtBlue]/root/example/[LtRed]files.zip[LtBlue]/numbers/[Reset][LtCyan]count.sh[Reset] -> [LtBlue]/etc/numbers/[Reset][LtGreen]count.sh[Reset]
1642zlrw-r--r--  999  Mon 01-May-2023 00:00:00  .gz   [LtBlue]/root/example/[LtRed]files.zip[LtBlue]/numbers/[Reset][LtCyan]googolplex.gz[Reset] -> [LtBlue]/etc/numbers/[Reset][LtRed]googolplex.gz[Reset]
1643zlrw-r--r--    0  Sat 01-Apr-2023 00:00:00        [LtBlue]/root/example/[LtRed]files.zip[LtBlue]/numbers/[Reset][LtCyan]ordinals[Reset] -> [LtBlue]/etc/numbers/[Reset][LtBlue]ordinals/[Reset]
1644zdrwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]/root/example/[LtRed]files.zip[LtBlue]/numbers/one two/[Reset]
1645z-rw-r--r--   70  Wed 01-Mar-2023 00:00:00  .txt  [LtBlue]/root/example/[LtRed]files.zip[LtBlue]/numbers/one two/[Reset]\"three\" 'four'.txt
1646";
1647        let files = create_files("", "/root", "");
1648        let files = modify_files_for_zip(files);
1649        let config = Config::default()
1650            .with_zip_expand(true)
1651            .with_show_precise(true)
1652            .with_abs_path(true);
1653        assert_eq!(expected, wrap_files(&config, false, &files));
1654    }
1655
1656    #[test]
1657    #[cfg(windows)]
1658    fn test_prints_paths_with_start_header_on_windows() {
1659        let expected = "\
1660Start            Sun 01-Jan-2023 00:00:00
1661-----------------------------------------
1662drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example\\[Reset]
1663-rwxr-xr-x   10  Wed 01-Nov-2023 00:00:00  .sh   [LtBlue]example\\[Reset][DkGreen]find.sh[Reset]
1664drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example\\files\\[Reset]
1665drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example\\files\\colours\\[Reset]
1666-rwxr--r--   20  Sun 01-Oct-2023 00:00:00  .sh   [LtBlue]example\\files\\colours\\[Reset][LtGreen]alpha.sh[Reset]
1667-rw-r--r--   30  Fri 01-Sep-2023 00:00:00  .txt  [LtBlue]example\\files\\colours\\[Reset]blue.txt
1668-rw-r--r--   40  Tue 01-Aug-2023 00:00:00  .txt  [LtBlue]example\\files\\colours\\[Reset]green.txt
1669-rw-r--r--   50  Sat 01-Jul-2023 00:00:00  .txt  [LtBlue]example\\files\\colours\\[Reset]red.txt
1670drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example\\files\\numbers\\[Reset]
1671lrwxr--r--   60  Thu 01-Jun-2023 00:00:00  .sh   [LtBlue]example\\files\\numbers\\[Reset][LtCyan]count.sh[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtGreen]count.sh[Reset]
1672lrw-r--r--  999  Mon 01-May-2023 00:00:00  .gz   [LtBlue]example\\files\\numbers\\[Reset][LtCyan]googolplex.gz[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtRed]googolplex.gz[Reset]
1673lrw-r--r--    0  Sat 01-Apr-2023 00:00:00        [LtBlue]example\\files\\numbers\\[Reset][LtCyan]ordinals[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtBlue]ordinals\\[Reset]
1674drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example\\files\\numbers\\one two\\[Reset]
1675-rw-r--r--   70  Wed 01-Mar-2023 00:00:00  .txt  [LtBlue]example\\files\\numbers\\one two\\[Reset]\"three\" 'four'.txt
1676";
1677        let files = create_files("D:", "/root", "");
1678        let config = Config::default()
1679            .with_filter_recent(RecentKind::Year(1))
1680            .with_show_precise(true)
1681            .with_abs_path(false);
1682        assert_eq!(expected, wrap_files(&config, false, &files));
1683    }
1684
1685    #[test]
1686    #[cfg(windows)]
1687    fn test_prints_paths_with_start_header_on_git_bash() {
1688        let expected = "\
1689Start            Sun 01-Jan-2023 00:00:00
1690-----------------------------------------
1691drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/[Reset]
1692-rwxr-xr-x   10  Wed 01-Nov-2023 00:00:00  .sh   [LtBlue]example/[Reset][DkGreen]find.sh[Reset]
1693drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/files/[Reset]
1694drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/files/colours/[Reset]
1695-rwxr--r--   20  Sun 01-Oct-2023 00:00:00  .sh   [LtBlue]example/files/colours/[Reset][LtGreen]alpha.sh[Reset]
1696-rw-r--r--   30  Fri 01-Sep-2023 00:00:00  .txt  [LtBlue]example/files/colours/[Reset]blue.txt
1697-rw-r--r--   40  Tue 01-Aug-2023 00:00:00  .txt  [LtBlue]example/files/colours/[Reset]green.txt
1698-rw-r--r--   50  Sat 01-Jul-2023 00:00:00  .txt  [LtBlue]example/files/colours/[Reset]red.txt
1699drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/files/numbers/[Reset]
1700lrwxr--r--   60  Thu 01-Jun-2023 00:00:00  .sh   [LtBlue]example/files/numbers/[Reset][LtCyan]count.sh[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtGreen]count.sh[Reset]
1701lrw-r--r--  999  Mon 01-May-2023 00:00:00  .gz   [LtBlue]example/files/numbers/[Reset][LtCyan]googolplex.gz[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtRed]googolplex.gz[Reset]
1702lrw-r--r--    0  Sat 01-Apr-2023 00:00:00        [LtBlue]example/files/numbers/[Reset][LtCyan]ordinals[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtBlue]ordinals/[Reset]
1703drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/files/numbers/one two/[Reset]
1704-rw-r--r--   70  Wed 01-Mar-2023 00:00:00  .txt  [LtBlue]example/files/numbers/one two/[Reset]\"three\" 'four'.txt
1705";
1706        let files = create_files("D:", "/root", "");
1707        let config = Config::default()
1708            .with_filter_recent(RecentKind::Year(1))
1709            .with_show_precise(true)
1710            .with_abs_path(false);
1711        assert_eq!(expected, wrap_files(&config, true, &files));
1712    }
1713
1714    #[test]
1715    #[cfg(not(windows))]
1716    fn test_prints_paths_with_start_header_on_linux() {
1717        let expected = "\
1718Start            Sun 01-Jan-2023 00:00:00
1719-----------------------------------------
1720drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/[Reset]
1721-rwxr-xr-x   10  Wed 01-Nov-2023 00:00:00  .sh   [LtBlue]example/[Reset][DkGreen]find.sh[Reset]
1722drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/files/[Reset]
1723drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/files/colours/[Reset]
1724-rwxr--r--   20  Sun 01-Oct-2023 00:00:00  .sh   [LtBlue]example/files/colours/[Reset][LtGreen]alpha.sh[Reset]
1725-rw-r--r--   30  Fri 01-Sep-2023 00:00:00  .txt  [LtBlue]example/files/colours/[Reset]blue.txt
1726-rw-r--r--   40  Tue 01-Aug-2023 00:00:00  .txt  [LtBlue]example/files/colours/[Reset]green.txt
1727-rw-r--r--   50  Sat 01-Jul-2023 00:00:00  .txt  [LtBlue]example/files/colours/[Reset]red.txt
1728drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/files/numbers/[Reset]
1729lrwxr--r--   60  Thu 01-Jun-2023 00:00:00  .sh   [LtBlue]example/files/numbers/[Reset][LtCyan]count.sh[Reset] -> [LtBlue]/etc/numbers/[Reset][LtGreen]count.sh[Reset]
1730lrw-r--r--  999  Mon 01-May-2023 00:00:00  .gz   [LtBlue]example/files/numbers/[Reset][LtCyan]googolplex.gz[Reset] -> [LtBlue]/etc/numbers/[Reset][LtRed]googolplex.gz[Reset]
1731lrw-r--r--    0  Sat 01-Apr-2023 00:00:00        [LtBlue]example/files/numbers/[Reset][LtCyan]ordinals[Reset] -> [LtBlue]/etc/numbers/[Reset][LtBlue]ordinals/[Reset]
1732drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/files/numbers/one two/[Reset]
1733-rw-r--r--   70  Wed 01-Mar-2023 00:00:00  .txt  [LtBlue]example/files/numbers/one two/[Reset]\"three\" 'four'.txt
1734";
1735        let files = create_files("", "/root", "");
1736        let config = Config::default()
1737            .with_filter_recent(RecentKind::Year(1))
1738            .with_show_precise(true)
1739            .with_abs_path(false);
1740        assert_eq!(expected, wrap_files(&config, false, &files));
1741    }
1742
1743    #[test]
1744    #[cfg(windows)]
1745    fn test_prints_paths_with_start_header_and_utc_on_windows() {
1746        let expected = "\
1747Start            Sun 01-Jan-2023 00:00:00Z
1748------------------------------------------
1749drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00Z        [LtBlue]example\\[Reset]
1750-rwxr-xr-x   10  Wed 01-Nov-2023 00:00:00Z  .sh   [LtBlue]example\\[Reset][DkGreen]find.sh[Reset]
1751drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00Z        [LtBlue]example\\files\\[Reset]
1752drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00Z        [LtBlue]example\\files\\colours\\[Reset]
1753-rwxr--r--   20  Sun 01-Oct-2023 00:00:00Z  .sh   [LtBlue]example\\files\\colours\\[Reset][LtGreen]alpha.sh[Reset]
1754-rw-r--r--   30  Fri 01-Sep-2023 00:00:00Z  .txt  [LtBlue]example\\files\\colours\\[Reset]blue.txt
1755-rw-r--r--   40  Tue 01-Aug-2023 00:00:00Z  .txt  [LtBlue]example\\files\\colours\\[Reset]green.txt
1756-rw-r--r--   50  Sat 01-Jul-2023 00:00:00Z  .txt  [LtBlue]example\\files\\colours\\[Reset]red.txt
1757drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00Z        [LtBlue]example\\files\\numbers\\[Reset]
1758lrwxr--r--   60  Thu 01-Jun-2023 00:00:00Z  .sh   [LtBlue]example\\files\\numbers\\[Reset][LtCyan]count.sh[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtGreen]count.sh[Reset]
1759lrw-r--r--  999  Mon 01-May-2023 00:00:00Z  .gz   [LtBlue]example\\files\\numbers\\[Reset][LtCyan]googolplex.gz[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtRed]googolplex.gz[Reset]
1760lrw-r--r--    0  Sat 01-Apr-2023 00:00:00Z        [LtBlue]example\\files\\numbers\\[Reset][LtCyan]ordinals[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtBlue]ordinals\\[Reset]
1761drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00Z        [LtBlue]example\\files\\numbers\\one two\\[Reset]
1762-rw-r--r--   70  Wed 01-Mar-2023 00:00:00Z  .txt  [LtBlue]example\\files\\numbers\\one two\\[Reset]\"three\" 'four'.txt
1763";
1764        let files = create_files("D:", "/root", "");
1765        let config = Config::default()
1766            .with_filter_recent(RecentKind::Year(1))
1767            .with_show_precise(true)
1768            .with_show_utc(true)
1769            .with_abs_path(false);
1770        assert_eq!(expected, wrap_files(&config, false, &files));
1771    }
1772
1773    #[test]
1774    #[cfg(windows)]
1775    fn test_prints_paths_with_start_header_and_utc_on_git_bash() {
1776        let expected = "\
1777Start            Sun 01-Jan-2023 00:00:00Z
1778------------------------------------------
1779drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00Z        [LtBlue]example/[Reset]
1780-rwxr-xr-x   10  Wed 01-Nov-2023 00:00:00Z  .sh   [LtBlue]example/[Reset][DkGreen]find.sh[Reset]
1781drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00Z        [LtBlue]example/files/[Reset]
1782drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00Z        [LtBlue]example/files/colours/[Reset]
1783-rwxr--r--   20  Sun 01-Oct-2023 00:00:00Z  .sh   [LtBlue]example/files/colours/[Reset][LtGreen]alpha.sh[Reset]
1784-rw-r--r--   30  Fri 01-Sep-2023 00:00:00Z  .txt  [LtBlue]example/files/colours/[Reset]blue.txt
1785-rw-r--r--   40  Tue 01-Aug-2023 00:00:00Z  .txt  [LtBlue]example/files/colours/[Reset]green.txt
1786-rw-r--r--   50  Sat 01-Jul-2023 00:00:00Z  .txt  [LtBlue]example/files/colours/[Reset]red.txt
1787drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00Z        [LtBlue]example/files/numbers/[Reset]
1788lrwxr--r--   60  Thu 01-Jun-2023 00:00:00Z  .sh   [LtBlue]example/files/numbers/[Reset][LtCyan]count.sh[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtGreen]count.sh[Reset]
1789lrw-r--r--  999  Mon 01-May-2023 00:00:00Z  .gz   [LtBlue]example/files/numbers/[Reset][LtCyan]googolplex.gz[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtRed]googolplex.gz[Reset]
1790lrw-r--r--    0  Sat 01-Apr-2023 00:00:00Z        [LtBlue]example/files/numbers/[Reset][LtCyan]ordinals[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtBlue]ordinals/[Reset]
1791drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00Z        [LtBlue]example/files/numbers/one two/[Reset]
1792-rw-r--r--   70  Wed 01-Mar-2023 00:00:00Z  .txt  [LtBlue]example/files/numbers/one two/[Reset]\"three\" 'four'.txt
1793";
1794        let files = create_files("D:", "/root", "");
1795        let config = Config::default()
1796            .with_filter_recent(RecentKind::Year(1))
1797            .with_show_precise(true)
1798            .with_show_utc(true)
1799            .with_abs_path(false);
1800        assert_eq!(expected, wrap_files(&config, true, &files));
1801    }
1802
1803    #[test]
1804    #[cfg(not(windows))]
1805    fn test_prints_paths_with_start_header_and_utc_on_linux() {
1806        let expected = "\
1807Start            Sun 01-Jan-2023 00:00:00Z
1808------------------------------------------
1809drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00Z        [LtBlue]example/[Reset]
1810-rwxr-xr-x   10  Wed 01-Nov-2023 00:00:00Z  .sh   [LtBlue]example/[Reset][DkGreen]find.sh[Reset]
1811drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00Z        [LtBlue]example/files/[Reset]
1812drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00Z        [LtBlue]example/files/colours/[Reset]
1813-rwxr--r--   20  Sun 01-Oct-2023 00:00:00Z  .sh   [LtBlue]example/files/colours/[Reset][LtGreen]alpha.sh[Reset]
1814-rw-r--r--   30  Fri 01-Sep-2023 00:00:00Z  .txt  [LtBlue]example/files/colours/[Reset]blue.txt
1815-rw-r--r--   40  Tue 01-Aug-2023 00:00:00Z  .txt  [LtBlue]example/files/colours/[Reset]green.txt
1816-rw-r--r--   50  Sat 01-Jul-2023 00:00:00Z  .txt  [LtBlue]example/files/colours/[Reset]red.txt
1817drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00Z        [LtBlue]example/files/numbers/[Reset]
1818lrwxr--r--   60  Thu 01-Jun-2023 00:00:00Z  .sh   [LtBlue]example/files/numbers/[Reset][LtCyan]count.sh[Reset] -> [LtBlue]/etc/numbers/[Reset][LtGreen]count.sh[Reset]
1819lrw-r--r--  999  Mon 01-May-2023 00:00:00Z  .gz   [LtBlue]example/files/numbers/[Reset][LtCyan]googolplex.gz[Reset] -> [LtBlue]/etc/numbers/[Reset][LtRed]googolplex.gz[Reset]
1820lrw-r--r--    0  Sat 01-Apr-2023 00:00:00Z        [LtBlue]example/files/numbers/[Reset][LtCyan]ordinals[Reset] -> [LtBlue]/etc/numbers/[Reset][LtBlue]ordinals/[Reset]
1821drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00Z        [LtBlue]example/files/numbers/one two/[Reset]
1822-rw-r--r--   70  Wed 01-Mar-2023 00:00:00Z  .txt  [LtBlue]example/files/numbers/one two/[Reset]\"three\" 'four'.txt
1823";
1824        let files = create_files("", "/root", "");
1825        let config = Config::default()
1826            .with_filter_recent(RecentKind::Year(1))
1827            .with_show_precise(true)
1828            .with_show_utc(true)
1829            .with_abs_path(false);
1830        assert_eq!(expected, wrap_files(&config, false, &files));
1831    }
1832
1833    #[test]
1834    #[cfg(windows)]
1835    fn test_prints_paths_with_total_footer_on_windows() {
1836        let expected = "\
1837drwxr-xr-x        0  Sun 31-Dec-2023 00:00:00        [LtBlue]example\\[Reset]
1838-rwxr-xr-x       10  Wed 01-Nov-2023 00:00:00  .sh   [LtBlue]example\\[Reset][DkGreen]find.sh[Reset]
1839drwxr-xr-x        0  Sun 31-Dec-2023 00:00:00        [LtBlue]example\\files\\[Reset]
1840drwxr-xr-x        0  Sun 31-Dec-2023 00:00:00        [LtBlue]example\\files\\colours\\[Reset]
1841-rwxr--r--       20  Sun 01-Oct-2023 00:00:00  .sh   [LtBlue]example\\files\\colours\\[Reset][LtGreen]alpha.sh[Reset]
1842-rw-r--r--       30  Fri 01-Sep-2023 00:00:00  .txt  [LtBlue]example\\files\\colours\\[Reset]blue.txt
1843-rw-r--r--       40  Tue 01-Aug-2023 00:00:00  .txt  [LtBlue]example\\files\\colours\\[Reset]green.txt
1844-rw-r--r--       50  Sat 01-Jul-2023 00:00:00  .txt  [LtBlue]example\\files\\colours\\[Reset]red.txt
1845drwxr-xr-x        0  Sun 31-Dec-2023 00:00:00        [LtBlue]example\\files\\numbers\\[Reset]
1846lrwxr--r--       60  Thu 01-Jun-2023 00:00:00  .sh   [LtBlue]example\\files\\numbers\\[Reset][LtCyan]count.sh[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtGreen]count.sh[Reset]
1847lrw-r--r--      999  Mon 01-May-2023 00:00:00  .gz   [LtBlue]example\\files\\numbers\\[Reset][LtCyan]googolplex.gz[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtRed]googolplex.gz[Reset]
1848lrw-r--r--        0  Sat 01-Apr-2023 00:00:00        [LtBlue]example\\files\\numbers\\[Reset][LtCyan]ordinals[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtBlue]ordinals\\[Reset]
1849drwxr-xr-x        0  Sun 31-Dec-2023 00:00:00        [LtBlue]example\\files\\numbers\\one two\\[Reset]
1850-rw-r--r--       70  Wed 01-Mar-2023 00:00:00  .txt  [LtBlue]example\\files\\numbers\\one two\\[Reset]\"three\" 'four'.txt
1851---------------------------------------------
1852Total         1,279                                  9 files 5 directories
1853";
1854        let files = create_files("D:", "/root", "");
1855        let config = Config::default()
1856            .with_show_precise(true)
1857            .with_show_total(true)
1858            .with_abs_path(false);
1859        assert_eq!(expected, wrap_files(&config, false, &files));
1860    }
1861
1862    #[test]
1863    #[cfg(windows)]
1864    fn test_prints_paths_with_total_footer_on_git_bash() {
1865        let expected = "\
1866drwxr-xr-x        0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/[Reset]
1867-rwxr-xr-x       10  Wed 01-Nov-2023 00:00:00  .sh   [LtBlue]example/[Reset][DkGreen]find.sh[Reset]
1868drwxr-xr-x        0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/files/[Reset]
1869drwxr-xr-x        0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/files/colours/[Reset]
1870-rwxr--r--       20  Sun 01-Oct-2023 00:00:00  .sh   [LtBlue]example/files/colours/[Reset][LtGreen]alpha.sh[Reset]
1871-rw-r--r--       30  Fri 01-Sep-2023 00:00:00  .txt  [LtBlue]example/files/colours/[Reset]blue.txt
1872-rw-r--r--       40  Tue 01-Aug-2023 00:00:00  .txt  [LtBlue]example/files/colours/[Reset]green.txt
1873-rw-r--r--       50  Sat 01-Jul-2023 00:00:00  .txt  [LtBlue]example/files/colours/[Reset]red.txt
1874drwxr-xr-x        0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/files/numbers/[Reset]
1875lrwxr--r--       60  Thu 01-Jun-2023 00:00:00  .sh   [LtBlue]example/files/numbers/[Reset][LtCyan]count.sh[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtGreen]count.sh[Reset]
1876lrw-r--r--      999  Mon 01-May-2023 00:00:00  .gz   [LtBlue]example/files/numbers/[Reset][LtCyan]googolplex.gz[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtRed]googolplex.gz[Reset]
1877lrw-r--r--        0  Sat 01-Apr-2023 00:00:00        [LtBlue]example/files/numbers/[Reset][LtCyan]ordinals[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtBlue]ordinals/[Reset]
1878drwxr-xr-x        0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/files/numbers/one two/[Reset]
1879-rw-r--r--       70  Wed 01-Mar-2023 00:00:00  .txt  [LtBlue]example/files/numbers/one two/[Reset]\"three\" 'four'.txt
1880---------------------------------------------
1881Total         1,279                                  9 files 5 directories
1882";
1883        let files = create_files("D:", "/root", "");
1884        let config = Config::default()
1885            .with_show_precise(true)
1886            .with_show_total(true)
1887            .with_abs_path(false);
1888        assert_eq!(expected, wrap_files(&config, true, &files));
1889    }
1890
1891    #[test]
1892    #[cfg(not(windows))]
1893    fn test_prints_paths_with_total_footer_on_linux() {
1894        let expected = "\
1895drwxr-xr-x        0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/[Reset]
1896-rwxr-xr-x       10  Wed 01-Nov-2023 00:00:00  .sh   [LtBlue]example/[Reset][DkGreen]find.sh[Reset]
1897drwxr-xr-x        0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/files/[Reset]
1898drwxr-xr-x        0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/files/colours/[Reset]
1899-rwxr--r--       20  Sun 01-Oct-2023 00:00:00  .sh   [LtBlue]example/files/colours/[Reset][LtGreen]alpha.sh[Reset]
1900-rw-r--r--       30  Fri 01-Sep-2023 00:00:00  .txt  [LtBlue]example/files/colours/[Reset]blue.txt
1901-rw-r--r--       40  Tue 01-Aug-2023 00:00:00  .txt  [LtBlue]example/files/colours/[Reset]green.txt
1902-rw-r--r--       50  Sat 01-Jul-2023 00:00:00  .txt  [LtBlue]example/files/colours/[Reset]red.txt
1903drwxr-xr-x        0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/files/numbers/[Reset]
1904lrwxr--r--       60  Thu 01-Jun-2023 00:00:00  .sh   [LtBlue]example/files/numbers/[Reset][LtCyan]count.sh[Reset] -> [LtBlue]/etc/numbers/[Reset][LtGreen]count.sh[Reset]
1905lrw-r--r--      999  Mon 01-May-2023 00:00:00  .gz   [LtBlue]example/files/numbers/[Reset][LtCyan]googolplex.gz[Reset] -> [LtBlue]/etc/numbers/[Reset][LtRed]googolplex.gz[Reset]
1906lrw-r--r--        0  Sat 01-Apr-2023 00:00:00        [LtBlue]example/files/numbers/[Reset][LtCyan]ordinals[Reset] -> [LtBlue]/etc/numbers/[Reset][LtBlue]ordinals/[Reset]
1907drwxr-xr-x        0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/files/numbers/one two/[Reset]
1908-rw-r--r--       70  Wed 01-Mar-2023 00:00:00  .txt  [LtBlue]example/files/numbers/one two/[Reset]\"three\" 'four'.txt
1909---------------------------------------------
1910Total         1,279                                  9 files 5 directories
1911";
1912        let files = create_files("", "/root", "");
1913        let config = Config::default()
1914            .with_show_precise(true)
1915            .with_show_total(true)
1916            .with_abs_path(false);
1917        assert_eq!(expected, wrap_files(&config, false, &files));
1918    }
1919
1920    #[test]
1921    #[cfg(windows)]
1922    fn test_prints_pretty_fields_on_windows() {
1923        let expected = "\
1924drwxr-xr-x    0 B    1 day          [LtBlue]example\\[Reset]
1925-rwxr-xr-x   10 B    2 month  .sh   [LtBlue]example\\[Reset][DkGreen]find.sh[Reset]
1926drwxr-xr-x    0 B    1 day          [LtBlue]example\\files\\[Reset]
1927drwxr-xr-x    0 B    1 day          [LtBlue]example\\files\\colours\\[Reset]
1928-rwxr--r--   20 B    3 month  .sh   [LtBlue]example\\files\\colours\\[Reset][LtGreen]alpha.sh[Reset]
1929-rw-r--r--   30 B    4 month  .txt  [LtBlue]example\\files\\colours\\[Reset]blue.txt
1930-rw-r--r--   40 B    5 month  .txt  [LtBlue]example\\files\\colours\\[Reset]green.txt
1931-rw-r--r--   50 B    6 month  .txt  [LtBlue]example\\files\\colours\\[Reset]red.txt
1932drwxr-xr-x    0 B    1 day          [LtBlue]example\\files\\numbers\\[Reset]
1933lrwxr--r--   60 B    7 month  .sh   [LtBlue]example\\files\\numbers\\[Reset][LtCyan]count.sh[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtGreen]count.sh[Reset]
1934lrw-r--r--  999 B    8 month  .gz   [LtBlue]example\\files\\numbers\\[Reset][LtCyan]googolplex.gz[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtRed]googolplex.gz[Reset]
1935lrw-r--r--    0 B    9 month        [LtBlue]example\\files\\numbers\\[Reset][LtCyan]ordinals[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtBlue]ordinals\\[Reset]
1936drwxr-xr-x    0 B    1 day          [LtBlue]example\\files\\numbers\\one two\\[Reset]
1937-rw-r--r--   70 B   10 month  .txt  [LtBlue]example\\files\\numbers\\one two\\[Reset]\"three\" 'four'.txt
1938";
1939        let files = create_files("D:", "/root", "");
1940        let config = Config::default()
1941            .with_curr_time(2024, 1, 1, 0, 0, 0)
1942            .with_show_precise(false)
1943            .with_abs_path(false);
1944        assert_eq!(expected, wrap_files(&config, false, &files));
1945    }
1946
1947    #[test]
1948    #[cfg(windows)]
1949    fn test_prints_pretty_fields_on_git_bash() {
1950        let expected = "\
1951drwxr-xr-x    0 B    1 day          [LtBlue]example/[Reset]
1952-rwxr-xr-x   10 B    2 month  .sh   [LtBlue]example/[Reset][DkGreen]find.sh[Reset]
1953drwxr-xr-x    0 B    1 day          [LtBlue]example/files/[Reset]
1954drwxr-xr-x    0 B    1 day          [LtBlue]example/files/colours/[Reset]
1955-rwxr--r--   20 B    3 month  .sh   [LtBlue]example/files/colours/[Reset][LtGreen]alpha.sh[Reset]
1956-rw-r--r--   30 B    4 month  .txt  [LtBlue]example/files/colours/[Reset]blue.txt
1957-rw-r--r--   40 B    5 month  .txt  [LtBlue]example/files/colours/[Reset]green.txt
1958-rw-r--r--   50 B    6 month  .txt  [LtBlue]example/files/colours/[Reset]red.txt
1959drwxr-xr-x    0 B    1 day          [LtBlue]example/files/numbers/[Reset]
1960lrwxr--r--   60 B    7 month  .sh   [LtBlue]example/files/numbers/[Reset][LtCyan]count.sh[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtGreen]count.sh[Reset]
1961lrw-r--r--  999 B    8 month  .gz   [LtBlue]example/files/numbers/[Reset][LtCyan]googolplex.gz[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtRed]googolplex.gz[Reset]
1962lrw-r--r--    0 B    9 month        [LtBlue]example/files/numbers/[Reset][LtCyan]ordinals[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtBlue]ordinals/[Reset]
1963drwxr-xr-x    0 B    1 day          [LtBlue]example/files/numbers/one two/[Reset]
1964-rw-r--r--   70 B   10 month  .txt  [LtBlue]example/files/numbers/one two/[Reset]\"three\" 'four'.txt
1965";
1966        let files = create_files("D:", "/root", "");
1967        let config = Config::default()
1968            .with_curr_time(2024, 1, 1, 0, 0, 0)
1969            .with_show_precise(false)
1970            .with_abs_path(false);
1971        assert_eq!(expected, wrap_files(&config, true, &files));
1972    }
1973
1974    #[test]
1975    #[cfg(not(windows))]
1976    fn test_prints_pretty_fields_on_linux() {
1977        let expected = "\
1978drwxr-xr-x    0 B    1 day          [LtBlue]example/[Reset]
1979-rwxr-xr-x   10 B    2 month  .sh   [LtBlue]example/[Reset][DkGreen]find.sh[Reset]
1980drwxr-xr-x    0 B    1 day          [LtBlue]example/files/[Reset]
1981drwxr-xr-x    0 B    1 day          [LtBlue]example/files/colours/[Reset]
1982-rwxr--r--   20 B    3 month  .sh   [LtBlue]example/files/colours/[Reset][LtGreen]alpha.sh[Reset]
1983-rw-r--r--   30 B    4 month  .txt  [LtBlue]example/files/colours/[Reset]blue.txt
1984-rw-r--r--   40 B    5 month  .txt  [LtBlue]example/files/colours/[Reset]green.txt
1985-rw-r--r--   50 B    6 month  .txt  [LtBlue]example/files/colours/[Reset]red.txt
1986drwxr-xr-x    0 B    1 day          [LtBlue]example/files/numbers/[Reset]
1987lrwxr--r--   60 B    7 month  .sh   [LtBlue]example/files/numbers/[Reset][LtCyan]count.sh[Reset] -> [LtBlue]/etc/numbers/[Reset][LtGreen]count.sh[Reset]
1988lrw-r--r--  999 B    8 month  .gz   [LtBlue]example/files/numbers/[Reset][LtCyan]googolplex.gz[Reset] -> [LtBlue]/etc/numbers/[Reset][LtRed]googolplex.gz[Reset]
1989lrw-r--r--    0 B    9 month        [LtBlue]example/files/numbers/[Reset][LtCyan]ordinals[Reset] -> [LtBlue]/etc/numbers/[Reset][LtBlue]ordinals/[Reset]
1990drwxr-xr-x    0 B    1 day          [LtBlue]example/files/numbers/one two/[Reset]
1991-rw-r--r--   70 B   10 month  .txt  [LtBlue]example/files/numbers/one two/[Reset]\"three\" 'four'.txt
1992";
1993        let files = create_files("", "/root", "");
1994        let config = Config::default()
1995            .with_curr_time(2024, 1, 1, 0, 0, 0)
1996            .with_show_precise(false)
1997            .with_abs_path(false);
1998        assert_eq!(expected, wrap_files(&config, false, &files));
1999    }
2000
2001    #[test]
2002    #[cfg(windows)]
2003    fn test_prints_pretty_fields_with_header_and_footer_on_windows() {
2004        let expected = "\
2005Start                1 year
2006----------------------------
2007drwxr-xr-x    0 B    1 day          [LtBlue]example\\[Reset]
2008-rwxr-xr-x   10 B    2 month  .sh   [LtBlue]example\\[Reset][DkGreen]find.sh[Reset]
2009drwxr-xr-x    0 B    1 day          [LtBlue]example\\files\\[Reset]
2010drwxr-xr-x    0 B    1 day          [LtBlue]example\\files\\colours\\[Reset]
2011-rwxr--r--   20 B    3 month  .sh   [LtBlue]example\\files\\colours\\[Reset][LtGreen]alpha.sh[Reset]
2012-rw-r--r--   30 B    4 month  .txt  [LtBlue]example\\files\\colours\\[Reset]blue.txt
2013-rw-r--r--   40 B    5 month  .txt  [LtBlue]example\\files\\colours\\[Reset]green.txt
2014-rw-r--r--   50 B    6 month  .txt  [LtBlue]example\\files\\colours\\[Reset]red.txt
2015drwxr-xr-x    0 B    1 day          [LtBlue]example\\files\\numbers\\[Reset]
2016lrwxr--r--   60 B    7 month  .sh   [LtBlue]example\\files\\numbers\\[Reset][LtCyan]count.sh[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtGreen]count.sh[Reset]
2017lrw-r--r--  999 B    8 month  .gz   [LtBlue]example\\files\\numbers\\[Reset][LtCyan]googolplex.gz[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtRed]googolplex.gz[Reset]
2018lrw-r--r--    0 B    9 month        [LtBlue]example\\files\\numbers\\[Reset][LtCyan]ordinals[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtBlue]ordinals\\[Reset]
2019drwxr-xr-x    0 B    1 day          [LtBlue]example\\files\\numbers\\one two\\[Reset]
2020-rw-r--r--   70 B   10 month  .txt  [LtBlue]example\\files\\numbers\\one two\\[Reset]\"three\" 'four'.txt
2021----------------------------
2022Total         1 KB                  9 files 5 directories
2023";
2024        let files = create_files("D:", "/root", "");
2025        let config = Config::default()
2026            .with_curr_time(2024, 1, 1, 0, 0, 0)
2027            .with_filter_recent(RecentKind::Year(1))
2028            .with_show_precise(false)
2029            .with_show_total(true)
2030            .with_abs_path(false);
2031        assert_eq!(expected, wrap_files(&config, false, &files));
2032    }
2033
2034    #[test]
2035    #[cfg(windows)]
2036    fn test_prints_pretty_fields_with_header_and_footer_on_git_bash() {
2037        let expected = "\
2038Start                1 year
2039----------------------------
2040drwxr-xr-x    0 B    1 day          [LtBlue]example/[Reset]
2041-rwxr-xr-x   10 B    2 month  .sh   [LtBlue]example/[Reset][DkGreen]find.sh[Reset]
2042drwxr-xr-x    0 B    1 day          [LtBlue]example/files/[Reset]
2043drwxr-xr-x    0 B    1 day          [LtBlue]example/files/colours/[Reset]
2044-rwxr--r--   20 B    3 month  .sh   [LtBlue]example/files/colours/[Reset][LtGreen]alpha.sh[Reset]
2045-rw-r--r--   30 B    4 month  .txt  [LtBlue]example/files/colours/[Reset]blue.txt
2046-rw-r--r--   40 B    5 month  .txt  [LtBlue]example/files/colours/[Reset]green.txt
2047-rw-r--r--   50 B    6 month  .txt  [LtBlue]example/files/colours/[Reset]red.txt
2048drwxr-xr-x    0 B    1 day          [LtBlue]example/files/numbers/[Reset]
2049lrwxr--r--   60 B    7 month  .sh   [LtBlue]example/files/numbers/[Reset][LtCyan]count.sh[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtGreen]count.sh[Reset]
2050lrw-r--r--  999 B    8 month  .gz   [LtBlue]example/files/numbers/[Reset][LtCyan]googolplex.gz[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtRed]googolplex.gz[Reset]
2051lrw-r--r--    0 B    9 month        [LtBlue]example/files/numbers/[Reset][LtCyan]ordinals[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtBlue]ordinals/[Reset]
2052drwxr-xr-x    0 B    1 day          [LtBlue]example/files/numbers/one two/[Reset]
2053-rw-r--r--   70 B   10 month  .txt  [LtBlue]example/files/numbers/one two/[Reset]\"three\" 'four'.txt
2054----------------------------
2055Total         1 KB                  9 files 5 directories
2056";
2057        let files = create_files("D:", "/root", "");
2058        let config = Config::default()
2059            .with_curr_time(2024, 1, 1, 0, 0, 0)
2060            .with_filter_recent(RecentKind::Year(1))
2061            .with_show_precise(false)
2062            .with_show_total(true)
2063            .with_abs_path(false);
2064        assert_eq!(expected, wrap_files(&config, true, &files));
2065    }
2066
2067    #[test]
2068    #[cfg(not(windows))]
2069    fn test_prints_pretty_fields_with_header_and_footer_on_linux() {
2070        let expected = "\
2071Start                1 year
2072----------------------------
2073drwxr-xr-x    0 B    1 day          [LtBlue]example/[Reset]
2074-rwxr-xr-x   10 B    2 month  .sh   [LtBlue]example/[Reset][DkGreen]find.sh[Reset]
2075drwxr-xr-x    0 B    1 day          [LtBlue]example/files/[Reset]
2076drwxr-xr-x    0 B    1 day          [LtBlue]example/files/colours/[Reset]
2077-rwxr--r--   20 B    3 month  .sh   [LtBlue]example/files/colours/[Reset][LtGreen]alpha.sh[Reset]
2078-rw-r--r--   30 B    4 month  .txt  [LtBlue]example/files/colours/[Reset]blue.txt
2079-rw-r--r--   40 B    5 month  .txt  [LtBlue]example/files/colours/[Reset]green.txt
2080-rw-r--r--   50 B    6 month  .txt  [LtBlue]example/files/colours/[Reset]red.txt
2081drwxr-xr-x    0 B    1 day          [LtBlue]example/files/numbers/[Reset]
2082lrwxr--r--   60 B    7 month  .sh   [LtBlue]example/files/numbers/[Reset][LtCyan]count.sh[Reset] -> [LtBlue]/etc/numbers/[Reset][LtGreen]count.sh[Reset]
2083lrw-r--r--  999 B    8 month  .gz   [LtBlue]example/files/numbers/[Reset][LtCyan]googolplex.gz[Reset] -> [LtBlue]/etc/numbers/[Reset][LtRed]googolplex.gz[Reset]
2084lrw-r--r--    0 B    9 month        [LtBlue]example/files/numbers/[Reset][LtCyan]ordinals[Reset] -> [LtBlue]/etc/numbers/[Reset][LtBlue]ordinals/[Reset]
2085drwxr-xr-x    0 B    1 day          [LtBlue]example/files/numbers/one two/[Reset]
2086-rw-r--r--   70 B   10 month  .txt  [LtBlue]example/files/numbers/one two/[Reset]\"three\" 'four'.txt
2087----------------------------
2088Total         1 KB                  9 files 5 directories
2089";
2090        let files = create_files("", "/root", "");
2091        let config = Config::default()
2092            .with_curr_time(2024, 1, 1, 0, 0, 0)
2093            .with_filter_recent(RecentKind::Year(1))
2094            .with_show_precise(false)
2095            .with_show_total(true)
2096            .with_abs_path(false);
2097        assert_eq!(expected, wrap_files(&config, false, &files));
2098    }
2099
2100    #[test]
2101    #[cfg(windows)]
2102    fn test_prints_git_flags_on_windows() {
2103        let expected = "\
2104drwxr-xr-x -----    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example\\[Reset]
2105-rwxr-xr-x AMRUI   10  Wed 01-Nov-2023 00:00:00  .sh   [LtBlue]example\\[Reset][DkGreen]find.sh[Reset]
2106drwxr-xr-x -----    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example\\files\\[Reset]
2107drwxr-xr-x -----    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example\\files\\colours\\[Reset]
2108-rwxr--r-- A----   20  Sun 01-Oct-2023 00:00:00  .sh   [LtBlue]example\\files\\colours\\[Reset][LtGreen]alpha.sh[Reset]
2109-rw-r--r-- -M---   30  Fri 01-Sep-2023 00:00:00  .txt  [LtBlue]example\\files\\colours\\[Reset]blue.txt
2110-rw-r--r-- --R--   40  Tue 01-Aug-2023 00:00:00  .txt  [LtBlue]example\\files\\colours\\[Reset]green.txt
2111-rw-r--r-- ---U-   50  Sat 01-Jul-2023 00:00:00  .txt  [LtBlue]example\\files\\colours\\[Reset]red.txt
2112drwxr-xr-x -----    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example\\files\\numbers\\[Reset]
2113lrwxr--r-- -----   60  Thu 01-Jun-2023 00:00:00  .sh   [LtBlue]example\\files\\numbers\\[Reset][LtCyan]count.sh[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtGreen]count.sh[Reset]
2114lrw-r--r-- -----  999  Mon 01-May-2023 00:00:00  .gz   [LtBlue]example\\files\\numbers\\[Reset][LtCyan]googolplex.gz[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtRed]googolplex.gz[Reset]
2115lrw-r--r-- -----    0  Sat 01-Apr-2023 00:00:00        [LtBlue]example\\files\\numbers\\[Reset][LtCyan]ordinals[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtBlue]ordinals\\[Reset]
2116drwxr-xr-x -----    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example\\files\\numbers\\one two\\[Reset]
2117-rw-r--r-- ----I   70  Wed 01-Mar-2023 00:00:00  .txt  [LtBlue]example\\files\\numbers\\one two\\[Reset]\"three\" 'four'.txt
2118";
2119        let files = create_files("D:", "/root", "");
2120        let config = Config::default()
2121            .with_filter_git(GitFlags::default())
2122            .with_show_precise(true);
2123        assert_eq!(expected, wrap_files(&config, false, &files));
2124    }
2125
2126    #[test]
2127    #[cfg(windows)]
2128    fn test_prints_git_flags_on_git_bash() {
2129        let expected = "\
2130drwxr-xr-x -----    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/[Reset]
2131-rwxr-xr-x AMRUI   10  Wed 01-Nov-2023 00:00:00  .sh   [LtBlue]example/[Reset][DkGreen]find.sh[Reset]
2132drwxr-xr-x -----    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/files/[Reset]
2133drwxr-xr-x -----    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/files/colours/[Reset]
2134-rwxr--r-- A----   20  Sun 01-Oct-2023 00:00:00  .sh   [LtBlue]example/files/colours/[Reset][LtGreen]alpha.sh[Reset]
2135-rw-r--r-- -M---   30  Fri 01-Sep-2023 00:00:00  .txt  [LtBlue]example/files/colours/[Reset]blue.txt
2136-rw-r--r-- --R--   40  Tue 01-Aug-2023 00:00:00  .txt  [LtBlue]example/files/colours/[Reset]green.txt
2137-rw-r--r-- ---U-   50  Sat 01-Jul-2023 00:00:00  .txt  [LtBlue]example/files/colours/[Reset]red.txt
2138drwxr-xr-x -----    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/files/numbers/[Reset]
2139lrwxr--r-- -----   60  Thu 01-Jun-2023 00:00:00  .sh   [LtBlue]example/files/numbers/[Reset][LtCyan]count.sh[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtGreen]count.sh[Reset]
2140lrw-r--r-- -----  999  Mon 01-May-2023 00:00:00  .gz   [LtBlue]example/files/numbers/[Reset][LtCyan]googolplex.gz[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtRed]googolplex.gz[Reset]
2141lrw-r--r-- -----    0  Sat 01-Apr-2023 00:00:00        [LtBlue]example/files/numbers/[Reset][LtCyan]ordinals[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtBlue]ordinals/[Reset]
2142drwxr-xr-x -----    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/files/numbers/one two/[Reset]
2143-rw-r--r-- ----I   70  Wed 01-Mar-2023 00:00:00  .txt  [LtBlue]example/files/numbers/one two/[Reset]\"three\" 'four'.txt
2144";
2145        let files = create_files("D:", "/root", "");
2146        let config = Config::default()
2147            .with_filter_git(GitFlags::default())
2148            .with_show_precise(true);
2149        assert_eq!(expected, wrap_files(&config, true, &files));
2150    }
2151
2152    #[test]
2153    #[cfg(not(windows))]
2154    fn test_prints_git_flags_on_linux() {
2155        let expected = "\
2156drwxr-xr-x -----    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/[Reset]
2157-rwxr-xr-x AMRUI   10  Wed 01-Nov-2023 00:00:00  .sh   [LtBlue]example/[Reset][DkGreen]find.sh[Reset]
2158drwxr-xr-x -----    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/files/[Reset]
2159drwxr-xr-x -----    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/files/colours/[Reset]
2160-rwxr--r-- A----   20  Sun 01-Oct-2023 00:00:00  .sh   [LtBlue]example/files/colours/[Reset][LtGreen]alpha.sh[Reset]
2161-rw-r--r-- -M---   30  Fri 01-Sep-2023 00:00:00  .txt  [LtBlue]example/files/colours/[Reset]blue.txt
2162-rw-r--r-- --R--   40  Tue 01-Aug-2023 00:00:00  .txt  [LtBlue]example/files/colours/[Reset]green.txt
2163-rw-r--r-- ---U-   50  Sat 01-Jul-2023 00:00:00  .txt  [LtBlue]example/files/colours/[Reset]red.txt
2164drwxr-xr-x -----    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/files/numbers/[Reset]
2165lrwxr--r-- -----   60  Thu 01-Jun-2023 00:00:00  .sh   [LtBlue]example/files/numbers/[Reset][LtCyan]count.sh[Reset] -> [LtBlue]/etc/numbers/[Reset][LtGreen]count.sh[Reset]
2166lrw-r--r-- -----  999  Mon 01-May-2023 00:00:00  .gz   [LtBlue]example/files/numbers/[Reset][LtCyan]googolplex.gz[Reset] -> [LtBlue]/etc/numbers/[Reset][LtRed]googolplex.gz[Reset]
2167lrw-r--r-- -----    0  Sat 01-Apr-2023 00:00:00        [LtBlue]example/files/numbers/[Reset][LtCyan]ordinals[Reset] -> [LtBlue]/etc/numbers/[Reset][LtBlue]ordinals/[Reset]
2168drwxr-xr-x -----    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/files/numbers/one two/[Reset]
2169-rw-r--r-- ----I   70  Wed 01-Mar-2023 00:00:00  .txt  [LtBlue]example/files/numbers/one two/[Reset]\"three\" 'four'.txt
2170";
2171        let files = create_files("", "/root", "");
2172        let config = Config::default()
2173            .with_filter_git(GitFlags::default())
2174            .with_show_precise(true);
2175        assert_eq!(expected, wrap_files(&config, false, &files));
2176    }
2177
2178    #[test]
2179    #[cfg(windows)]
2180    fn test_prints_git_flags_with_header_and_footer_on_windows() {
2181        let expected = "\
2182Start                      Sun 01-Jan-2023 00:00:00
2183---------------------------------------------------
2184drwxr-xr-x -----        0  Sun 31-Dec-2023 00:00:00        [LtBlue]example\\[Reset]
2185-rwxr-xr-x AMRUI       10  Wed 01-Nov-2023 00:00:00  .sh   [LtBlue]example\\[Reset][DkGreen]find.sh[Reset]
2186drwxr-xr-x -----        0  Sun 31-Dec-2023 00:00:00        [LtBlue]example\\files\\[Reset]
2187drwxr-xr-x -----        0  Sun 31-Dec-2023 00:00:00        [LtBlue]example\\files\\colours\\[Reset]
2188-rwxr--r-- A----       20  Sun 01-Oct-2023 00:00:00  .sh   [LtBlue]example\\files\\colours\\[Reset][LtGreen]alpha.sh[Reset]
2189-rw-r--r-- -M---       30  Fri 01-Sep-2023 00:00:00  .txt  [LtBlue]example\\files\\colours\\[Reset]blue.txt
2190-rw-r--r-- --R--       40  Tue 01-Aug-2023 00:00:00  .txt  [LtBlue]example\\files\\colours\\[Reset]green.txt
2191-rw-r--r-- ---U-       50  Sat 01-Jul-2023 00:00:00  .txt  [LtBlue]example\\files\\colours\\[Reset]red.txt
2192drwxr-xr-x -----        0  Sun 31-Dec-2023 00:00:00        [LtBlue]example\\files\\numbers\\[Reset]
2193lrwxr--r-- -----       60  Thu 01-Jun-2023 00:00:00  .sh   [LtBlue]example\\files\\numbers\\[Reset][LtCyan]count.sh[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtGreen]count.sh[Reset]
2194lrw-r--r-- -----      999  Mon 01-May-2023 00:00:00  .gz   [LtBlue]example\\files\\numbers\\[Reset][LtCyan]googolplex.gz[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtRed]googolplex.gz[Reset]
2195lrw-r--r-- -----        0  Sat 01-Apr-2023 00:00:00        [LtBlue]example\\files\\numbers\\[Reset][LtCyan]ordinals[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtBlue]ordinals\\[Reset]
2196drwxr-xr-x -----        0  Sun 31-Dec-2023 00:00:00        [LtBlue]example\\files\\numbers\\one two\\[Reset]
2197-rw-r--r-- ----I       70  Wed 01-Mar-2023 00:00:00  .txt  [LtBlue]example\\files\\numbers\\one two\\[Reset]\"three\" 'four'.txt
2198---------------------------------------------------
2199Total               1,279                                  9 files 5 directories
2200";
2201        let files = create_files("D:", "/root", "");
2202        let config = Config::default()
2203            .with_filter_recent(RecentKind::Year(1))
2204            .with_show_precise(true)
2205            .with_show_total(true)
2206            .with_filter_git(GitFlags::default());
2207        assert_eq!(expected, wrap_files(&config, false, &files));
2208    }
2209
2210    #[test]
2211    #[cfg(windows)]
2212    fn test_prints_git_flags_with_header_and_footer_on_git_bash() {
2213        let expected = "\
2214Start                      Sun 01-Jan-2023 00:00:00
2215---------------------------------------------------
2216drwxr-xr-x -----        0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/[Reset]
2217-rwxr-xr-x AMRUI       10  Wed 01-Nov-2023 00:00:00  .sh   [LtBlue]example/[Reset][DkGreen]find.sh[Reset]
2218drwxr-xr-x -----        0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/files/[Reset]
2219drwxr-xr-x -----        0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/files/colours/[Reset]
2220-rwxr--r-- A----       20  Sun 01-Oct-2023 00:00:00  .sh   [LtBlue]example/files/colours/[Reset][LtGreen]alpha.sh[Reset]
2221-rw-r--r-- -M---       30  Fri 01-Sep-2023 00:00:00  .txt  [LtBlue]example/files/colours/[Reset]blue.txt
2222-rw-r--r-- --R--       40  Tue 01-Aug-2023 00:00:00  .txt  [LtBlue]example/files/colours/[Reset]green.txt
2223-rw-r--r-- ---U-       50  Sat 01-Jul-2023 00:00:00  .txt  [LtBlue]example/files/colours/[Reset]red.txt
2224drwxr-xr-x -----        0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/files/numbers/[Reset]
2225lrwxr--r-- -----       60  Thu 01-Jun-2023 00:00:00  .sh   [LtBlue]example/files/numbers/[Reset][LtCyan]count.sh[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtGreen]count.sh[Reset]
2226lrw-r--r-- -----      999  Mon 01-May-2023 00:00:00  .gz   [LtBlue]example/files/numbers/[Reset][LtCyan]googolplex.gz[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtRed]googolplex.gz[Reset]
2227lrw-r--r-- -----        0  Sat 01-Apr-2023 00:00:00        [LtBlue]example/files/numbers/[Reset][LtCyan]ordinals[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtBlue]ordinals/[Reset]
2228drwxr-xr-x -----        0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/files/numbers/one two/[Reset]
2229-rw-r--r-- ----I       70  Wed 01-Mar-2023 00:00:00  .txt  [LtBlue]example/files/numbers/one two/[Reset]\"three\" 'four'.txt
2230---------------------------------------------------
2231Total               1,279                                  9 files 5 directories
2232";
2233        let files = create_files("D:", "/root", "");
2234        let config = Config::default()
2235            .with_filter_recent(RecentKind::Year(1))
2236            .with_show_precise(true)
2237            .with_show_total(true)
2238            .with_filter_git(GitFlags::default());
2239        assert_eq!(expected, wrap_files(&config, true, &files));
2240    }
2241
2242    #[test]
2243    #[cfg(not(windows))]
2244    fn test_prints_git_flags_with_header_and_footer_on_linux() {
2245        let expected = "\
2246Start                      Sun 01-Jan-2023 00:00:00
2247---------------------------------------------------
2248drwxr-xr-x -----        0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/[Reset]
2249-rwxr-xr-x AMRUI       10  Wed 01-Nov-2023 00:00:00  .sh   [LtBlue]example/[Reset][DkGreen]find.sh[Reset]
2250drwxr-xr-x -----        0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/files/[Reset]
2251drwxr-xr-x -----        0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/files/colours/[Reset]
2252-rwxr--r-- A----       20  Sun 01-Oct-2023 00:00:00  .sh   [LtBlue]example/files/colours/[Reset][LtGreen]alpha.sh[Reset]
2253-rw-r--r-- -M---       30  Fri 01-Sep-2023 00:00:00  .txt  [LtBlue]example/files/colours/[Reset]blue.txt
2254-rw-r--r-- --R--       40  Tue 01-Aug-2023 00:00:00  .txt  [LtBlue]example/files/colours/[Reset]green.txt
2255-rw-r--r-- ---U-       50  Sat 01-Jul-2023 00:00:00  .txt  [LtBlue]example/files/colours/[Reset]red.txt
2256drwxr-xr-x -----        0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/files/numbers/[Reset]
2257lrwxr--r-- -----       60  Thu 01-Jun-2023 00:00:00  .sh   [LtBlue]example/files/numbers/[Reset][LtCyan]count.sh[Reset] -> [LtBlue]/etc/numbers/[Reset][LtGreen]count.sh[Reset]
2258lrw-r--r-- -----      999  Mon 01-May-2023 00:00:00  .gz   [LtBlue]example/files/numbers/[Reset][LtCyan]googolplex.gz[Reset] -> [LtBlue]/etc/numbers/[Reset][LtRed]googolplex.gz[Reset]
2259lrw-r--r-- -----        0  Sat 01-Apr-2023 00:00:00        [LtBlue]example/files/numbers/[Reset][LtCyan]ordinals[Reset] -> [LtBlue]/etc/numbers/[Reset][LtBlue]ordinals/[Reset]
2260drwxr-xr-x -----        0  Sun 31-Dec-2023 00:00:00        [LtBlue]example/files/numbers/one two/[Reset]
2261-rw-r--r-- ----I       70  Wed 01-Mar-2023 00:00:00  .txt  [LtBlue]example/files/numbers/one two/[Reset]\"three\" 'four'.txt
2262---------------------------------------------------
2263Total               1,279                                  9 files 5 directories
2264";
2265        let files = create_files("", "/root", "");
2266        let config = Config::default()
2267            .with_filter_recent(RecentKind::Year(1))
2268            .with_show_precise(true)
2269            .with_show_total(true)
2270            .with_filter_git(GitFlags::default());
2271        assert_eq!(expected, wrap_files(&config, false, &files));
2272    }
2273
2274    #[test]
2275    #[cfg(windows)]
2276    fn test_prints_file_signature_on_windows() {
2277        let expected = "\
2278drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00  00000000 ....        [LtBlue]example\\[Reset]
2279-rwxr-xr-x   10  Wed 01-Nov-2023 00:00:00  23212f75 #!/u  .sh   [LtBlue]example\\[Reset][DkGreen]find.sh[Reset]
2280drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00  00000000 ....        [LtBlue]example\\files\\[Reset]
2281drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00  00000000 ....        [LtBlue]example\\files\\colours\\[Reset]
2282-rwxr--r--   20  Sun 01-Oct-2023 00:00:00  23212f75 #!/u  .sh   [LtBlue]example\\files\\colours\\[Reset][LtGreen]alpha.sh[Reset]
2283-rw-r--r--   30  Fri 01-Sep-2023 00:00:00  424c5545 BLUE  .txt  [LtBlue]example\\files\\colours\\[Reset]blue.txt
2284-rw-r--r--   40  Tue 01-Aug-2023 00:00:00  47524545 GREE  .txt  [LtBlue]example\\files\\colours\\[Reset]green.txt
2285-rw-r--r--   50  Sat 01-Jul-2023 00:00:00  52454400 RED.  .txt  [LtBlue]example\\files\\colours\\[Reset]red.txt
2286drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00  00000000 ....        [LtBlue]example\\files\\numbers\\[Reset]
2287lrwxr--r--   60  Thu 01-Jun-2023 00:00:00  23212f75 #!/u  .sh   [LtBlue]example\\files\\numbers\\[Reset][LtCyan]count.sh[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtGreen]count.sh[Reset]
2288lrw-r--r--  999  Mon 01-May-2023 00:00:00  00000000 ....  .gz   [LtBlue]example\\files\\numbers\\[Reset][LtCyan]googolplex.gz[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtRed]googolplex.gz[Reset]
2289lrw-r--r--    0  Sat 01-Apr-2023 00:00:00  00000000 ....        [LtBlue]example\\files\\numbers\\[Reset][LtCyan]ordinals[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtBlue]ordinals\\[Reset]
2290drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00  00000000 ....        [LtBlue]example\\files\\numbers\\one two\\[Reset]
2291-rw-r--r--   70  Wed 01-Mar-2023 00:00:00  fffe3334 ..34  .txt  [LtBlue]example\\files\\numbers\\one two\\[Reset]\"three\" 'four'.txt
2292";
2293        let files = create_files("D:", "/root", "");
2294        let config = Config::default()
2295            .with_show_precise(true)
2296            .with_show_sig(true);
2297        assert_eq!(expected, wrap_files(&config, false, &files));
2298    }
2299
2300    #[test]
2301    #[cfg(windows)]
2302    fn test_prints_file_signature_on_git_bash() {
2303        let expected = "\
2304drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00  00000000 ....        [LtBlue]example/[Reset]
2305-rwxr-xr-x   10  Wed 01-Nov-2023 00:00:00  23212f75 #!/u  .sh   [LtBlue]example/[Reset][DkGreen]find.sh[Reset]
2306drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00  00000000 ....        [LtBlue]example/files/[Reset]
2307drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00  00000000 ....        [LtBlue]example/files/colours/[Reset]
2308-rwxr--r--   20  Sun 01-Oct-2023 00:00:00  23212f75 #!/u  .sh   [LtBlue]example/files/colours/[Reset][LtGreen]alpha.sh[Reset]
2309-rw-r--r--   30  Fri 01-Sep-2023 00:00:00  424c5545 BLUE  .txt  [LtBlue]example/files/colours/[Reset]blue.txt
2310-rw-r--r--   40  Tue 01-Aug-2023 00:00:00  47524545 GREE  .txt  [LtBlue]example/files/colours/[Reset]green.txt
2311-rw-r--r--   50  Sat 01-Jul-2023 00:00:00  52454400 RED.  .txt  [LtBlue]example/files/colours/[Reset]red.txt
2312drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00  00000000 ....        [LtBlue]example/files/numbers/[Reset]
2313lrwxr--r--   60  Thu 01-Jun-2023 00:00:00  23212f75 #!/u  .sh   [LtBlue]example/files/numbers/[Reset][LtCyan]count.sh[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtGreen]count.sh[Reset]
2314lrw-r--r--  999  Mon 01-May-2023 00:00:00  00000000 ....  .gz   [LtBlue]example/files/numbers/[Reset][LtCyan]googolplex.gz[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtRed]googolplex.gz[Reset]
2315lrw-r--r--    0  Sat 01-Apr-2023 00:00:00  00000000 ....        [LtBlue]example/files/numbers/[Reset][LtCyan]ordinals[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtBlue]ordinals/[Reset]
2316drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00  00000000 ....        [LtBlue]example/files/numbers/one two/[Reset]
2317-rw-r--r--   70  Wed 01-Mar-2023 00:00:00  fffe3334 ..34  .txt  [LtBlue]example/files/numbers/one two/[Reset]\"three\" 'four'.txt
2318";
2319        let files = create_files("D:", "/root", "");
2320        let config = Config::default()
2321            .with_show_precise(true)
2322            .with_show_sig(true);
2323        assert_eq!(expected, wrap_files(&config, true, &files));
2324    }
2325
2326    #[test]
2327    #[cfg(not(windows))]
2328    fn test_prints_file_signature_on_linux() {
2329        let expected = "\
2330drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00  00000000 ....        [LtBlue]example/[Reset]
2331-rwxr-xr-x   10  Wed 01-Nov-2023 00:00:00  23212f75 #!/u  .sh   [LtBlue]example/[Reset][DkGreen]find.sh[Reset]
2332drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00  00000000 ....        [LtBlue]example/files/[Reset]
2333drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00  00000000 ....        [LtBlue]example/files/colours/[Reset]
2334-rwxr--r--   20  Sun 01-Oct-2023 00:00:00  23212f75 #!/u  .sh   [LtBlue]example/files/colours/[Reset][LtGreen]alpha.sh[Reset]
2335-rw-r--r--   30  Fri 01-Sep-2023 00:00:00  424c5545 BLUE  .txt  [LtBlue]example/files/colours/[Reset]blue.txt
2336-rw-r--r--   40  Tue 01-Aug-2023 00:00:00  47524545 GREE  .txt  [LtBlue]example/files/colours/[Reset]green.txt
2337-rw-r--r--   50  Sat 01-Jul-2023 00:00:00  52454400 RED.  .txt  [LtBlue]example/files/colours/[Reset]red.txt
2338drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00  00000000 ....        [LtBlue]example/files/numbers/[Reset]
2339lrwxr--r--   60  Thu 01-Jun-2023 00:00:00  23212f75 #!/u  .sh   [LtBlue]example/files/numbers/[Reset][LtCyan]count.sh[Reset] -> [LtBlue]/etc/numbers/[Reset][LtGreen]count.sh[Reset]
2340lrw-r--r--  999  Mon 01-May-2023 00:00:00  00000000 ....  .gz   [LtBlue]example/files/numbers/[Reset][LtCyan]googolplex.gz[Reset] -> [LtBlue]/etc/numbers/[Reset][LtRed]googolplex.gz[Reset]
2341lrw-r--r--    0  Sat 01-Apr-2023 00:00:00  00000000 ....        [LtBlue]example/files/numbers/[Reset][LtCyan]ordinals[Reset] -> [LtBlue]/etc/numbers/[Reset][LtBlue]ordinals/[Reset]
2342drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00  00000000 ....        [LtBlue]example/files/numbers/one two/[Reset]
2343-rw-r--r--   70  Wed 01-Mar-2023 00:00:00  fffe3334 ..34  .txt  [LtBlue]example/files/numbers/one two/[Reset]\"three\" 'four'.txt
2344";
2345        let files = create_files("", "/root", "");
2346        let config = Config::default()
2347            .with_show_precise(true)
2348            .with_show_sig(true);
2349        assert_eq!(expected, wrap_files(&config, false, &files));
2350    }
2351
2352    #[test]
2353    #[cfg(windows)]
2354    fn test_prints_file_signature_with_header_and_footer_on_windows() {
2355        let expected = "\
2356Start                Sun 01-Jan-2023 00:00:00
2357---------------------------------------------
2358drwxr-xr-x        0  Sun 31-Dec-2023 00:00:00  00000000 ....        [LtBlue]example\\[Reset]
2359-rwxr-xr-x       10  Wed 01-Nov-2023 00:00:00  23212f75 #!/u  .sh   [LtBlue]example\\[Reset][DkGreen]find.sh[Reset]
2360drwxr-xr-x        0  Sun 31-Dec-2023 00:00:00  00000000 ....        [LtBlue]example\\files\\[Reset]
2361drwxr-xr-x        0  Sun 31-Dec-2023 00:00:00  00000000 ....        [LtBlue]example\\files\\colours\\[Reset]
2362-rwxr--r--       20  Sun 01-Oct-2023 00:00:00  23212f75 #!/u  .sh   [LtBlue]example\\files\\colours\\[Reset][LtGreen]alpha.sh[Reset]
2363-rw-r--r--       30  Fri 01-Sep-2023 00:00:00  424c5545 BLUE  .txt  [LtBlue]example\\files\\colours\\[Reset]blue.txt
2364-rw-r--r--       40  Tue 01-Aug-2023 00:00:00  47524545 GREE  .txt  [LtBlue]example\\files\\colours\\[Reset]green.txt
2365-rw-r--r--       50  Sat 01-Jul-2023 00:00:00  52454400 RED.  .txt  [LtBlue]example\\files\\colours\\[Reset]red.txt
2366drwxr-xr-x        0  Sun 31-Dec-2023 00:00:00  00000000 ....        [LtBlue]example\\files\\numbers\\[Reset]
2367lrwxr--r--       60  Thu 01-Jun-2023 00:00:00  23212f75 #!/u  .sh   [LtBlue]example\\files\\numbers\\[Reset][LtCyan]count.sh[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtGreen]count.sh[Reset]
2368lrw-r--r--      999  Mon 01-May-2023 00:00:00  00000000 ....  .gz   [LtBlue]example\\files\\numbers\\[Reset][LtCyan]googolplex.gz[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtRed]googolplex.gz[Reset]
2369lrw-r--r--        0  Sat 01-Apr-2023 00:00:00  00000000 ....        [LtBlue]example\\files\\numbers\\[Reset][LtCyan]ordinals[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtBlue]ordinals\\[Reset]
2370drwxr-xr-x        0  Sun 31-Dec-2023 00:00:00  00000000 ....        [LtBlue]example\\files\\numbers\\one two\\[Reset]
2371-rw-r--r--       70  Wed 01-Mar-2023 00:00:00  fffe3334 ..34  .txt  [LtBlue]example\\files\\numbers\\one two\\[Reset]\"three\" 'four'.txt
2372---------------------------------------------
2373Total         1,279                                                 9 files 5 directories
2374";
2375        let files = create_files("D:", "/root", "");
2376        let config = Config::default()
2377            .with_filter_recent(RecentKind::Year(1))
2378            .with_show_precise(true)
2379            .with_show_total(true)
2380            .with_show_sig(true);
2381        assert_eq!(expected, wrap_files(&config, false, &files));
2382    }
2383
2384    #[test]
2385    #[cfg(windows)]
2386    fn test_prints_file_signature_with_header_and_footer_on_git_bash() {
2387        let expected = "\
2388Start                Sun 01-Jan-2023 00:00:00
2389---------------------------------------------
2390drwxr-xr-x        0  Sun 31-Dec-2023 00:00:00  00000000 ....        [LtBlue]example/[Reset]
2391-rwxr-xr-x       10  Wed 01-Nov-2023 00:00:00  23212f75 #!/u  .sh   [LtBlue]example/[Reset][DkGreen]find.sh[Reset]
2392drwxr-xr-x        0  Sun 31-Dec-2023 00:00:00  00000000 ....        [LtBlue]example/files/[Reset]
2393drwxr-xr-x        0  Sun 31-Dec-2023 00:00:00  00000000 ....        [LtBlue]example/files/colours/[Reset]
2394-rwxr--r--       20  Sun 01-Oct-2023 00:00:00  23212f75 #!/u  .sh   [LtBlue]example/files/colours/[Reset][LtGreen]alpha.sh[Reset]
2395-rw-r--r--       30  Fri 01-Sep-2023 00:00:00  424c5545 BLUE  .txt  [LtBlue]example/files/colours/[Reset]blue.txt
2396-rw-r--r--       40  Tue 01-Aug-2023 00:00:00  47524545 GREE  .txt  [LtBlue]example/files/colours/[Reset]green.txt
2397-rw-r--r--       50  Sat 01-Jul-2023 00:00:00  52454400 RED.  .txt  [LtBlue]example/files/colours/[Reset]red.txt
2398drwxr-xr-x        0  Sun 31-Dec-2023 00:00:00  00000000 ....        [LtBlue]example/files/numbers/[Reset]
2399lrwxr--r--       60  Thu 01-Jun-2023 00:00:00  23212f75 #!/u  .sh   [LtBlue]example/files/numbers/[Reset][LtCyan]count.sh[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtGreen]count.sh[Reset]
2400lrw-r--r--      999  Mon 01-May-2023 00:00:00  00000000 ....  .gz   [LtBlue]example/files/numbers/[Reset][LtCyan]googolplex.gz[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtRed]googolplex.gz[Reset]
2401lrw-r--r--        0  Sat 01-Apr-2023 00:00:00  00000000 ....        [LtBlue]example/files/numbers/[Reset][LtCyan]ordinals[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtBlue]ordinals/[Reset]
2402drwxr-xr-x        0  Sun 31-Dec-2023 00:00:00  00000000 ....        [LtBlue]example/files/numbers/one two/[Reset]
2403-rw-r--r--       70  Wed 01-Mar-2023 00:00:00  fffe3334 ..34  .txt  [LtBlue]example/files/numbers/one two/[Reset]\"three\" 'four'.txt
2404---------------------------------------------
2405Total         1,279                                                 9 files 5 directories
2406";
2407        let files = create_files("D:", "/root", "");
2408        let config = Config::default()
2409            .with_filter_recent(RecentKind::Year(1))
2410            .with_show_precise(true)
2411            .with_show_total(true)
2412            .with_show_sig(true);
2413        assert_eq!(expected, wrap_files(&config, true, &files));
2414    }
2415
2416    #[test]
2417    #[cfg(not(windows))]
2418    fn test_prints_file_signature_with_header_and_footer_on_linux() {
2419        let expected = "\
2420Start                Sun 01-Jan-2023 00:00:00
2421---------------------------------------------
2422drwxr-xr-x        0  Sun 31-Dec-2023 00:00:00  00000000 ....        [LtBlue]example/[Reset]
2423-rwxr-xr-x       10  Wed 01-Nov-2023 00:00:00  23212f75 #!/u  .sh   [LtBlue]example/[Reset][DkGreen]find.sh[Reset]
2424drwxr-xr-x        0  Sun 31-Dec-2023 00:00:00  00000000 ....        [LtBlue]example/files/[Reset]
2425drwxr-xr-x        0  Sun 31-Dec-2023 00:00:00  00000000 ....        [LtBlue]example/files/colours/[Reset]
2426-rwxr--r--       20  Sun 01-Oct-2023 00:00:00  23212f75 #!/u  .sh   [LtBlue]example/files/colours/[Reset][LtGreen]alpha.sh[Reset]
2427-rw-r--r--       30  Fri 01-Sep-2023 00:00:00  424c5545 BLUE  .txt  [LtBlue]example/files/colours/[Reset]blue.txt
2428-rw-r--r--       40  Tue 01-Aug-2023 00:00:00  47524545 GREE  .txt  [LtBlue]example/files/colours/[Reset]green.txt
2429-rw-r--r--       50  Sat 01-Jul-2023 00:00:00  52454400 RED.  .txt  [LtBlue]example/files/colours/[Reset]red.txt
2430drwxr-xr-x        0  Sun 31-Dec-2023 00:00:00  00000000 ....        [LtBlue]example/files/numbers/[Reset]
2431lrwxr--r--       60  Thu 01-Jun-2023 00:00:00  23212f75 #!/u  .sh   [LtBlue]example/files/numbers/[Reset][LtCyan]count.sh[Reset] -> [LtBlue]/etc/numbers/[Reset][LtGreen]count.sh[Reset]
2432lrw-r--r--      999  Mon 01-May-2023 00:00:00  00000000 ....  .gz   [LtBlue]example/files/numbers/[Reset][LtCyan]googolplex.gz[Reset] -> [LtBlue]/etc/numbers/[Reset][LtRed]googolplex.gz[Reset]
2433lrw-r--r--        0  Sat 01-Apr-2023 00:00:00  00000000 ....        [LtBlue]example/files/numbers/[Reset][LtCyan]ordinals[Reset] -> [LtBlue]/etc/numbers/[Reset][LtBlue]ordinals/[Reset]
2434drwxr-xr-x        0  Sun 31-Dec-2023 00:00:00  00000000 ....        [LtBlue]example/files/numbers/one two/[Reset]
2435-rw-r--r--       70  Wed 01-Mar-2023 00:00:00  fffe3334 ..34  .txt  [LtBlue]example/files/numbers/one two/[Reset]\"three\" 'four'.txt
2436---------------------------------------------
2437Total         1,279                                                 9 files 5 directories
2438";
2439        let files = create_files("", "/root", "");
2440        let config = Config::default()
2441            .with_filter_recent(RecentKind::Year(1))
2442            .with_show_precise(true)
2443            .with_show_total(true)
2444            .with_show_sig(true);
2445        assert_eq!(expected, wrap_files(&config, false, &files));
2446    }
2447
2448    #[test]
2449    #[cfg(not(windows))]
2450    #[cfg(unix)]
2451    fn test_prints_owner_information_on_linux() {
2452        let expected = "\
2453drwxr-xr-x  alice public    0 B    1 day          [LtBlue]example/[Reset]
2454-rwxr-xr-x  root  root     10 B    2 month  .sh   [LtBlue]example/[Reset][DkGreen]find.sh[Reset]
2455drwxr-xr-x  alice public    0 B    1 day          [LtBlue]example/files/[Reset]
2456drwxr-xr-x  alice public    0 B    1 day          [LtBlue]example/files/colours/[Reset]
2457-rwxr--r--  alice public   20 B    3 month  .sh   [LtBlue]example/files/colours/[Reset][LtGreen]alpha.sh[Reset]
2458-rw-r--r--  alice public   30 B    4 month  .txt  [LtBlue]example/files/colours/[Reset]blue.txt
2459-rw-r--r--  alice public   40 B    5 month  .txt  [LtBlue]example/files/colours/[Reset]green.txt
2460-rw-r--r--  alice public   50 B    6 month  .txt  [LtBlue]example/files/colours/[Reset]red.txt
2461drwxr-xr-x  bob   public    0 B    1 day          [LtBlue]example/files/numbers/[Reset]
2462lrwxr--r--  bob   public   60 B    7 month  .sh   [LtBlue]example/files/numbers/[Reset][LtCyan]count.sh[Reset] -> [LtBlue]/etc/numbers/[Reset][LtGreen]count.sh[Reset]
2463lrw-r--r--  bob   public  999 B    8 month  .gz   [LtBlue]example/files/numbers/[Reset][LtCyan]googolplex.gz[Reset] -> [LtBlue]/etc/numbers/[Reset][LtRed]googolplex.gz[Reset]
2464lrw-r--r--  bob   public    0 B    9 month        [LtBlue]example/files/numbers/[Reset][LtCyan]ordinals[Reset] -> [LtBlue]/etc/numbers/[Reset][LtBlue]ordinals/[Reset]
2465drwxr-xr-x  -     -         0 B    1 day          [LtBlue]example/files/numbers/one two/[Reset]
2466-rw-r--r--  -     -        70 B   10 month  .txt  [LtBlue]example/files/numbers/one two/[Reset]\"three\" 'four'.txt
2467";
2468        let files = create_files("", "/root", "");
2469        let config = Config::default()
2470            .with_curr_time(2024, 1, 1, 0, 0, 0)
2471            .with_show_precise(false)
2472            .with_show_owner(true)
2473            .with_abs_path(false);
2474        assert_eq!(expected, wrap_files(&config, false, &files));
2475    }
2476
2477    #[test]
2478    #[cfg(not(windows))]
2479    #[cfg(unix)]
2480    fn test_prints_owner_information_with_header_and_footer_on_linux() {
2481        let expected = "\
2482Start                              1 year
2483------------------------------------------
2484drwxr-xr-x  alice public    0 B    1 day          [LtBlue]example/[Reset]
2485-rwxr-xr-x  root  root     10 B    2 month  .sh   [LtBlue]example/[Reset][DkGreen]find.sh[Reset]
2486drwxr-xr-x  alice public    0 B    1 day          [LtBlue]example/files/[Reset]
2487drwxr-xr-x  alice public    0 B    1 day          [LtBlue]example/files/colours/[Reset]
2488-rwxr--r--  alice public   20 B    3 month  .sh   [LtBlue]example/files/colours/[Reset][LtGreen]alpha.sh[Reset]
2489-rw-r--r--  alice public   30 B    4 month  .txt  [LtBlue]example/files/colours/[Reset]blue.txt
2490-rw-r--r--  alice public   40 B    5 month  .txt  [LtBlue]example/files/colours/[Reset]green.txt
2491-rw-r--r--  alice public   50 B    6 month  .txt  [LtBlue]example/files/colours/[Reset]red.txt
2492drwxr-xr-x  bob   public    0 B    1 day          [LtBlue]example/files/numbers/[Reset]
2493lrwxr--r--  bob   public   60 B    7 month  .sh   [LtBlue]example/files/numbers/[Reset][LtCyan]count.sh[Reset] -> [LtBlue]/etc/numbers/[Reset][LtGreen]count.sh[Reset]
2494lrw-r--r--  bob   public  999 B    8 month  .gz   [LtBlue]example/files/numbers/[Reset][LtCyan]googolplex.gz[Reset] -> [LtBlue]/etc/numbers/[Reset][LtRed]googolplex.gz[Reset]
2495lrw-r--r--  bob   public    0 B    9 month        [LtBlue]example/files/numbers/[Reset][LtCyan]ordinals[Reset] -> [LtBlue]/etc/numbers/[Reset][LtBlue]ordinals/[Reset]
2496drwxr-xr-x  -     -         0 B    1 day          [LtBlue]example/files/numbers/one two/[Reset]
2497-rw-r--r--  -     -        70 B   10 month  .txt  [LtBlue]example/files/numbers/one two/[Reset]\"three\" 'four'.txt
2498------------------------------------------
2499Total                       1 KB                  9 files 5 directories
2500";
2501        let files = create_files("", "/root", "");
2502        let config = Config::default()
2503            .with_curr_time(2024, 1, 1, 0, 0, 0)
2504            .with_filter_recent(RecentKind::Year(1))
2505            .with_show_precise(false)
2506            .with_show_owner(true)
2507            .with_show_total(true)
2508            .with_abs_path(false);
2509        assert_eq!(expected, wrap_files(&config, false, &files));
2510    }
2511
2512    #[test]
2513    #[cfg(windows)]
2514    fn test_prints_version_numbers_on_windows() {
2515        let expected = "\
2516-rwxr--r--  999  Mon 01-Jan-2024 00:00:00  12.3.4.0   .exe  [LtGreen]binary.exe[Reset]
2517-rwxr--r--  999  Mon 01-Jan-2024 00:00:00  5.67.89.0  .dll  library.dll
2518-rw-r--r--  999  Mon 01-Jan-2024 00:00:00             .txt  readme.txt
2519";
2520        let files = create_files_with_version();
2521        let config = Config::default()
2522            .with_show_precise(true)
2523            .with_win_ver(true);
2524        assert_eq!(expected, wrap_files(&config, false, &files));
2525    }
2526
2527    #[test]
2528    #[cfg(windows)]
2529    fn test_prints_version_numbers_on_git_bash() {
2530        let expected = "\
2531-rwxr--r--  999  Mon 01-Jan-2024 00:00:00  12.3.4.0   .exe  [LtGreen]binary.exe[Reset]
2532-rwxr--r--  999  Mon 01-Jan-2024 00:00:00  5.67.89.0  .dll  library.dll
2533-rw-r--r--  999  Mon 01-Jan-2024 00:00:00             .txt  readme.txt
2534";
2535        let files = create_files_with_version();
2536        let config = Config::default()
2537            .with_show_precise(true)
2538            .with_win_ver(true);
2539        assert_eq!(expected, wrap_files(&config, true, &files));
2540    }
2541
2542    #[test]
2543    #[cfg(windows)]
2544    fn test_prints_relative_paths_no_attributes_on_windows() {
2545        let expected = "\
2546[LtBlue]example\\[Reset]
2547[LtBlue]example\\[Reset][DkGreen]find.sh[Reset]
2548[LtBlue]example\\files\\[Reset]
2549[LtBlue]example\\files\\colours\\[Reset]
2550[LtBlue]example\\files\\colours\\[Reset][LtGreen]alpha.sh[Reset]
2551[LtBlue]example\\files\\colours\\[Reset]blue.txt
2552[LtBlue]example\\files\\colours\\[Reset]green.txt
2553[LtBlue]example\\files\\colours\\[Reset]red.txt
2554[LtBlue]example\\files\\numbers\\[Reset]
2555[LtBlue]example\\files\\numbers\\[Reset][LtCyan]count.sh[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtGreen]count.sh[Reset]
2556[LtBlue]example\\files\\numbers\\[Reset][LtCyan]googolplex.gz[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtRed]googolplex.gz[Reset]
2557[LtBlue]example\\files\\numbers\\[Reset][LtCyan]ordinals[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtBlue]ordinals\\[Reset]
2558[LtBlue]example\\files\\numbers\\one two\\[Reset]
2559[LtBlue]example\\files\\numbers\\one two\\[Reset]\"three\" 'four'.txt
2560";
2561        let files = create_files("D:", "/root", "");
2562        let config = Config::default()
2563            .with_only_path(true)
2564            .with_abs_path(false);
2565        assert_eq!(expected, wrap_files(&config, false, &files));
2566    }
2567
2568    #[test]
2569    #[cfg(windows)]
2570    fn test_prints_relative_paths_no_attributes_on_git_bash() {
2571        let expected = "\
2572[LtBlue]example/[Reset]
2573[LtBlue]example/[Reset][DkGreen]find.sh[Reset]
2574[LtBlue]example/files/[Reset]
2575[LtBlue]example/files/colours/[Reset]
2576[LtBlue]example/files/colours/[Reset][LtGreen]alpha.sh[Reset]
2577[LtBlue]example/files/colours/[Reset]blue.txt
2578[LtBlue]example/files/colours/[Reset]green.txt
2579[LtBlue]example/files/colours/[Reset]red.txt
2580[LtBlue]example/files/numbers/[Reset]
2581[LtBlue]example/files/numbers/[Reset][LtCyan]count.sh[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtGreen]count.sh[Reset]
2582[LtBlue]example/files/numbers/[Reset][LtCyan]googolplex.gz[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtRed]googolplex.gz[Reset]
2583[LtBlue]example/files/numbers/[Reset][LtCyan]ordinals[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtBlue]ordinals/[Reset]
2584[LtBlue]example/files/numbers/one two/[Reset]
2585[LtBlue]example/files/numbers/one two/[Reset]\"three\" 'four'.txt
2586";
2587        let files = create_files("D:", "/root", "");
2588        let config = Config::default()
2589            .with_only_path(true)
2590            .with_abs_path(false);
2591        assert_eq!(expected, wrap_files(&config, true, &files));
2592    }
2593
2594    #[test]
2595    #[cfg(not(windows))]
2596    fn test_prints_relative_paths_no_attributes_on_linux() {
2597        let expected = "\
2598[LtBlue]example/[Reset]
2599[LtBlue]example/[Reset][DkGreen]find.sh[Reset]
2600[LtBlue]example/files/[Reset]
2601[LtBlue]example/files/colours/[Reset]
2602[LtBlue]example/files/colours/[Reset][LtGreen]alpha.sh[Reset]
2603[LtBlue]example/files/colours/[Reset]blue.txt
2604[LtBlue]example/files/colours/[Reset]green.txt
2605[LtBlue]example/files/colours/[Reset]red.txt
2606[LtBlue]example/files/numbers/[Reset]
2607[LtBlue]example/files/numbers/[Reset][LtCyan]count.sh[Reset] -> [LtBlue]/etc/numbers/[Reset][LtGreen]count.sh[Reset]
2608[LtBlue]example/files/numbers/[Reset][LtCyan]googolplex.gz[Reset] -> [LtBlue]/etc/numbers/[Reset][LtRed]googolplex.gz[Reset]
2609[LtBlue]example/files/numbers/[Reset][LtCyan]ordinals[Reset] -> [LtBlue]/etc/numbers/[Reset][LtBlue]ordinals/[Reset]
2610[LtBlue]example/files/numbers/one two/[Reset]
2611[LtBlue]example/files/numbers/one two/[Reset]\"three\" 'four'.txt
2612";
2613        let files = create_files("", "/root", "");
2614        let config = Config::default()
2615            .with_only_path(true)
2616            .with_abs_path(false);
2617        assert_eq!(expected, wrap_files(&config, false, &files));
2618    }
2619
2620    #[test]
2621    #[cfg(windows)]
2622    fn test_prints_absolute_paths_no_attributes_on_windows() {
2623        let expected = "\
2624[LtBlue]D:\\root\\example\\[Reset]
2625[LtBlue]D:\\root\\example\\[Reset][DkGreen]find.sh[Reset]
2626[LtBlue]D:\\root\\example\\files\\[Reset]
2627[LtBlue]D:\\root\\example\\files\\colours\\[Reset]
2628[LtBlue]D:\\root\\example\\files\\colours\\[Reset][LtGreen]alpha.sh[Reset]
2629[LtBlue]D:\\root\\example\\files\\colours\\[Reset]blue.txt
2630[LtBlue]D:\\root\\example\\files\\colours\\[Reset]green.txt
2631[LtBlue]D:\\root\\example\\files\\colours\\[Reset]red.txt
2632[LtBlue]D:\\root\\example\\files\\numbers\\[Reset]
2633[LtBlue]D:\\root\\example\\files\\numbers\\[Reset][LtCyan]count.sh[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtGreen]count.sh[Reset]
2634[LtBlue]D:\\root\\example\\files\\numbers\\[Reset][LtCyan]googolplex.gz[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtRed]googolplex.gz[Reset]
2635[LtBlue]D:\\root\\example\\files\\numbers\\[Reset][LtCyan]ordinals[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtBlue]ordinals\\[Reset]
2636[LtBlue]D:\\root\\example\\files\\numbers\\one two\\[Reset]
2637[LtBlue]D:\\root\\example\\files\\numbers\\one two\\[Reset]\"three\" 'four'.txt
2638";
2639        let files = create_files("D:", "/root", "");
2640        let config = Config::default()
2641            .with_only_path(true)
2642            .with_abs_path(true);
2643        assert_eq!(expected, wrap_files(&config, false, &files));
2644    }
2645
2646    #[test]
2647    #[cfg(windows)]
2648    fn test_prints_absolute_paths_no_attributes_on_git_bash() {
2649        let expected = "\
2650[LtBlue]/d/root/example/[Reset]
2651[LtBlue]/d/root/example/[Reset][DkGreen]find.sh[Reset]
2652[LtBlue]/d/root/example/files/[Reset]
2653[LtBlue]/d/root/example/files/colours/[Reset]
2654[LtBlue]/d/root/example/files/colours/[Reset][LtGreen]alpha.sh[Reset]
2655[LtBlue]/d/root/example/files/colours/[Reset]blue.txt
2656[LtBlue]/d/root/example/files/colours/[Reset]green.txt
2657[LtBlue]/d/root/example/files/colours/[Reset]red.txt
2658[LtBlue]/d/root/example/files/numbers/[Reset]
2659[LtBlue]/d/root/example/files/numbers/[Reset][LtCyan]count.sh[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtGreen]count.sh[Reset]
2660[LtBlue]/d/root/example/files/numbers/[Reset][LtCyan]googolplex.gz[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtRed]googolplex.gz[Reset]
2661[LtBlue]/d/root/example/files/numbers/[Reset][LtCyan]ordinals[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtBlue]ordinals/[Reset]
2662[LtBlue]/d/root/example/files/numbers/one two/[Reset]
2663[LtBlue]/d/root/example/files/numbers/one two/[Reset]\"three\" 'four'.txt
2664";
2665        let files = create_files("D:", "/root", "");
2666        let config = Config::default()
2667            .with_only_path(true)
2668            .with_abs_path(true);
2669        assert_eq!(expected, wrap_files(&config, true, &files));
2670    }
2671
2672    #[test]
2673    #[cfg(not(windows))]
2674    fn test_prints_absolute_paths_no_attributes_on_linux() {
2675        let expected = "\
2676[LtBlue]/root/example/[Reset]
2677[LtBlue]/root/example/[Reset][DkGreen]find.sh[Reset]
2678[LtBlue]/root/example/files/[Reset]
2679[LtBlue]/root/example/files/colours/[Reset]
2680[LtBlue]/root/example/files/colours/[Reset][LtGreen]alpha.sh[Reset]
2681[LtBlue]/root/example/files/colours/[Reset]blue.txt
2682[LtBlue]/root/example/files/colours/[Reset]green.txt
2683[LtBlue]/root/example/files/colours/[Reset]red.txt
2684[LtBlue]/root/example/files/numbers/[Reset]
2685[LtBlue]/root/example/files/numbers/[Reset][LtCyan]count.sh[Reset] -> [LtBlue]/etc/numbers/[Reset][LtGreen]count.sh[Reset]
2686[LtBlue]/root/example/files/numbers/[Reset][LtCyan]googolplex.gz[Reset] -> [LtBlue]/etc/numbers/[Reset][LtRed]googolplex.gz[Reset]
2687[LtBlue]/root/example/files/numbers/[Reset][LtCyan]ordinals[Reset] -> [LtBlue]/etc/numbers/[Reset][LtBlue]ordinals/[Reset]
2688[LtBlue]/root/example/files/numbers/one two/[Reset]
2689[LtBlue]/root/example/files/numbers/one two/[Reset]\"three\" 'four'.txt
2690";
2691        let files = create_files("", "/root", "");
2692        let config = Config::default()
2693            .with_only_path(true)
2694            .with_abs_path(true);
2695        assert_eq!(expected, wrap_files(&config, false, &files));
2696    }
2697
2698    #[test]
2699    #[cfg(windows)]
2700    fn test_prints_relative_paths_with_escaping_on_windows() {
2701        let expected = "\
2702[LtBlue]example\\[Reset]
2703[LtBlue]example\\[Reset][DkGreen]find.sh[Reset]
2704[LtBlue]example\\files\\[Reset]
2705[LtBlue]example\\files\\colours\\[Reset]
2706[LtBlue]example\\files\\colours\\[Reset][LtGreen]alpha.sh[Reset]
2707[LtBlue]example\\files\\colours\\[Reset]blue.txt
2708[LtBlue]example\\files\\colours\\[Reset]green.txt
2709[LtBlue]example\\files\\colours\\[Reset]red.txt
2710[LtBlue]example\\files\\numbers\\[Reset]
2711[LtBlue]example\\files\\numbers\\[Reset][LtCyan]count.sh[Reset]
2712[LtBlue]example\\files\\numbers\\[Reset][LtCyan]googolplex.gz[Reset]
2713[LtBlue]example\\files\\numbers\\[Reset][LtCyan]ordinals[Reset]
2714[LtBlue]example\\files\\numbers\\one two\\[Reset]
2715[LtBlue]example\\files\\numbers\\one two\\[Reset]\"three\" 'four'.txt
2716";
2717        let files = create_files("D:", "/root", "");
2718        let config = Config::default()
2719            .with_escape_path()
2720            .with_abs_path(false);
2721        assert_eq!(expected, wrap_files(&config, false, &files));
2722    }
2723
2724    #[test]
2725    #[cfg(windows)]
2726    fn test_prints_relative_paths_with_escaping_on_git_bash() {
2727        let expected = "\
2728[LtBlue]example/[Reset]
2729[LtBlue]example/[Reset][DkGreen]find.sh[Reset]
2730[LtBlue]example/files/[Reset]
2731[LtBlue]example/files/colours/[Reset]
2732[LtBlue]example/files/colours/[Reset][LtGreen]alpha.sh[Reset]
2733[LtBlue]example/files/colours/[Reset]blue.txt
2734[LtBlue]example/files/colours/[Reset]green.txt
2735[LtBlue]example/files/colours/[Reset]red.txt
2736[LtBlue]example/files/numbers/[Reset]
2737[LtBlue]example/files/numbers/[Reset][LtCyan]count.sh[Reset]
2738[LtBlue]example/files/numbers/[Reset][LtCyan]googolplex.gz[Reset]
2739[LtBlue]example/files/numbers/[Reset][LtCyan]ordinals[Reset]
2740[LtBlue]example/files/numbers/one\\ two/[Reset]
2741[LtBlue]example/files/numbers/one\\ two/[Reset]\\\"three\\\"\\ \\'four\\'.txt
2742";
2743        let files = create_files("D:", "/root", "");
2744        let config = Config::default()
2745            .with_escape_path()
2746            .with_abs_path(false);
2747        assert_eq!(expected, wrap_files(&config, true, &files));
2748    }
2749
2750    #[test]
2751    #[cfg(not(windows))]
2752    fn test_prints_relative_paths_with_escaping_on_linux() {
2753        let expected = "\
2754[LtBlue]example/[Reset]
2755[LtBlue]example/[Reset][DkGreen]find.sh[Reset]
2756[LtBlue]example/files/[Reset]
2757[LtBlue]example/files/colours/[Reset]
2758[LtBlue]example/files/colours/[Reset][LtGreen]alpha.sh[Reset]
2759[LtBlue]example/files/colours/[Reset]blue.txt
2760[LtBlue]example/files/colours/[Reset]green.txt
2761[LtBlue]example/files/colours/[Reset]red.txt
2762[LtBlue]example/files/numbers/[Reset]
2763[LtBlue]example/files/numbers/[Reset][LtCyan]count.sh[Reset]
2764[LtBlue]example/files/numbers/[Reset][LtCyan]googolplex.gz[Reset]
2765[LtBlue]example/files/numbers/[Reset][LtCyan]ordinals[Reset]
2766[LtBlue]example/files/numbers/one\\ two/[Reset]
2767[LtBlue]example/files/numbers/one\\ two/[Reset]\\\"three\\\"\\ \\'four\\'.txt
2768";
2769        let files = create_files("", "/root", "");
2770        let config = Config::default()
2771            .with_escape_path()
2772            .with_abs_path(false);
2773        assert_eq!(expected, wrap_files(&config, false, &files));
2774    }
2775
2776    #[test]
2777    #[cfg(windows)]
2778    fn test_prints_absolute_paths_with_escaping_on_windows() {
2779        let expected = "\
2780[LtBlue]D:\\root\\example\\[Reset]
2781[LtBlue]D:\\root\\example\\[Reset][DkGreen]find.sh[Reset]
2782[LtBlue]D:\\root\\example\\files\\[Reset]
2783[LtBlue]D:\\root\\example\\files\\colours\\[Reset]
2784[LtBlue]D:\\root\\example\\files\\colours\\[Reset][LtGreen]alpha.sh[Reset]
2785[LtBlue]D:\\root\\example\\files\\colours\\[Reset]blue.txt
2786[LtBlue]D:\\root\\example\\files\\colours\\[Reset]green.txt
2787[LtBlue]D:\\root\\example\\files\\colours\\[Reset]red.txt
2788[LtBlue]D:\\root\\example\\files\\numbers\\[Reset]
2789[LtBlue]D:\\root\\example\\files\\numbers\\[Reset][LtCyan]count.sh[Reset]
2790[LtBlue]D:\\root\\example\\files\\numbers\\[Reset][LtCyan]googolplex.gz[Reset]
2791[LtBlue]D:\\root\\example\\files\\numbers\\[Reset][LtCyan]ordinals[Reset]
2792[LtBlue]D:\\root\\example\\files\\numbers\\one two\\[Reset]
2793[LtBlue]D:\\root\\example\\files\\numbers\\one two\\[Reset]\"three\" 'four'.txt
2794";
2795        let files = create_files("D:", "/root", "");
2796        let config = Config::default()
2797            .with_escape_path()
2798            .with_abs_path(true);
2799        assert_eq!(expected, wrap_files(&config, false, &files));
2800    }
2801
2802    #[test]
2803    #[cfg(windows)]
2804    fn test_prints_absolute_paths_with_escaping_on_git_bash() {
2805        let expected = "\
2806[LtBlue]/d/root/example/[Reset]
2807[LtBlue]/d/root/example/[Reset][DkGreen]find.sh[Reset]
2808[LtBlue]/d/root/example/files/[Reset]
2809[LtBlue]/d/root/example/files/colours/[Reset]
2810[LtBlue]/d/root/example/files/colours/[Reset][LtGreen]alpha.sh[Reset]
2811[LtBlue]/d/root/example/files/colours/[Reset]blue.txt
2812[LtBlue]/d/root/example/files/colours/[Reset]green.txt
2813[LtBlue]/d/root/example/files/colours/[Reset]red.txt
2814[LtBlue]/d/root/example/files/numbers/[Reset]
2815[LtBlue]/d/root/example/files/numbers/[Reset][LtCyan]count.sh[Reset]
2816[LtBlue]/d/root/example/files/numbers/[Reset][LtCyan]googolplex.gz[Reset]
2817[LtBlue]/d/root/example/files/numbers/[Reset][LtCyan]ordinals[Reset]
2818[LtBlue]/d/root/example/files/numbers/one\\ two/[Reset]
2819[LtBlue]/d/root/example/files/numbers/one\\ two/[Reset]\\\"three\\\"\\ \\'four\\'.txt
2820";
2821        let files = create_files("D:", "/root", "");
2822        let config = Config::default()
2823            .with_escape_path()
2824            .with_abs_path(true);
2825        assert_eq!(expected, wrap_files(&config, true, &files));
2826    }
2827
2828    #[test]
2829    #[cfg(not(windows))]
2830    fn test_prints_absolute_paths_with_escaping_on_linux() {
2831        let expected = "\
2832[LtBlue]/root/example/[Reset]
2833[LtBlue]/root/example/[Reset][DkGreen]find.sh[Reset]
2834[LtBlue]/root/example/files/[Reset]
2835[LtBlue]/root/example/files/colours/[Reset]
2836[LtBlue]/root/example/files/colours/[Reset][LtGreen]alpha.sh[Reset]
2837[LtBlue]/root/example/files/colours/[Reset]blue.txt
2838[LtBlue]/root/example/files/colours/[Reset]green.txt
2839[LtBlue]/root/example/files/colours/[Reset]red.txt
2840[LtBlue]/root/example/files/numbers/[Reset]
2841[LtBlue]/root/example/files/numbers/[Reset][LtCyan]count.sh[Reset]
2842[LtBlue]/root/example/files/numbers/[Reset][LtCyan]googolplex.gz[Reset]
2843[LtBlue]/root/example/files/numbers/[Reset][LtCyan]ordinals[Reset]
2844[LtBlue]/root/example/files/numbers/one\\ two/[Reset]
2845[LtBlue]/root/example/files/numbers/one\\ two/[Reset]\\\"three\\\"\\ \\'four\\'.txt
2846";
2847        let files = create_files("", "/root", "");
2848        let config = Config::default()
2849            .with_escape_path()
2850            .with_abs_path(true);
2851        assert_eq!(expected, wrap_files(&config, false, &files));
2852    }
2853
2854    #[test]
2855    #[cfg(windows)]
2856    fn test_prints_relative_paths_sorted_by_name_on_windows() {
2857        let expected = "\
2858[LtGreen]alpha.sh[Reset] ([LtBlue]example\\files\\colours\\[Reset])
2859blue.txt ([LtBlue]example\\files\\colours\\[Reset])
2860[LtCyan]count.sh[Reset] ([LtBlue]example\\files\\numbers\\[Reset]) -> [LtBlue]D:\\etc\\numbers\\[Reset][LtGreen]count.sh[Reset]
2861[DkGreen]find.sh[Reset] ([LtBlue]example\\[Reset])
2862[LtCyan]googolplex.gz[Reset] ([LtBlue]example\\files\\numbers\\[Reset]) -> [LtBlue]D:\\etc\\numbers\\[Reset][LtRed]googolplex.gz[Reset]
2863green.txt ([LtBlue]example\\files\\colours\\[Reset])
2864[LtCyan]ordinals[Reset] ([LtBlue]example\\files\\numbers\\[Reset]) -> [LtBlue]D:\\etc\\numbers\\[Reset][LtBlue]ordinals\\[Reset]
2865red.txt ([LtBlue]example\\files\\colours\\[Reset])
2866\"three\" 'four'.txt ([LtBlue]example\\files\\numbers\\one two\\[Reset])
2867";
2868        let files = create_files("D:", "/root", "");
2869        let files = modify_files_by_name(files);
2870        let config = Config::default()
2871            .with_sort_name(true)
2872            .with_only_path(true)
2873            .with_abs_path(false);
2874        assert_eq!(expected, wrap_files(&config, false, &files));
2875    }
2876
2877    #[test]
2878    #[cfg(windows)]
2879    fn test_prints_relative_paths_sorted_by_name_on_git_bash() {
2880        let expected = "\
2881[LtGreen]alpha.sh[Reset] ([LtBlue]example/files/colours/[Reset])
2882blue.txt ([LtBlue]example/files/colours/[Reset])
2883[LtCyan]count.sh[Reset] ([LtBlue]example/files/numbers/[Reset]) -> [LtBlue]/d/etc/numbers/[Reset][LtGreen]count.sh[Reset]
2884[DkGreen]find.sh[Reset] ([LtBlue]example/[Reset])
2885[LtCyan]googolplex.gz[Reset] ([LtBlue]example/files/numbers/[Reset]) -> [LtBlue]/d/etc/numbers/[Reset][LtRed]googolplex.gz[Reset]
2886green.txt ([LtBlue]example/files/colours/[Reset])
2887[LtCyan]ordinals[Reset] ([LtBlue]example/files/numbers/[Reset]) -> [LtBlue]/d/etc/numbers/[Reset][LtBlue]ordinals/[Reset]
2888red.txt ([LtBlue]example/files/colours/[Reset])
2889\"three\" 'four'.txt ([LtBlue]example/files/numbers/one two/[Reset])
2890";
2891        let files = create_files("D:", "/root", "");
2892        let files = modify_files_by_name(files);
2893        let config = Config::default()
2894            .with_sort_name(true)
2895            .with_only_path(true)
2896            .with_abs_path(false);
2897        assert_eq!(expected, wrap_files(&config, true, &files));
2898    }
2899
2900    #[test]
2901    #[cfg(not(windows))]
2902    fn test_prints_relative_paths_sorted_by_name_on_linux() {
2903        let expected = "\
2904[LtGreen]alpha.sh[Reset] ([LtBlue]example/files/colours/[Reset])
2905blue.txt ([LtBlue]example/files/colours/[Reset])
2906[LtCyan]count.sh[Reset] ([LtBlue]example/files/numbers/[Reset]) -> [LtBlue]/etc/numbers/[Reset][LtGreen]count.sh[Reset]
2907[DkGreen]find.sh[Reset] ([LtBlue]example/[Reset])
2908[LtCyan]googolplex.gz[Reset] ([LtBlue]example/files/numbers/[Reset]) -> [LtBlue]/etc/numbers/[Reset][LtRed]googolplex.gz[Reset]
2909green.txt ([LtBlue]example/files/colours/[Reset])
2910[LtCyan]ordinals[Reset] ([LtBlue]example/files/numbers/[Reset]) -> [LtBlue]/etc/numbers/[Reset][LtBlue]ordinals/[Reset]
2911red.txt ([LtBlue]example/files/colours/[Reset])
2912\"three\" 'four'.txt ([LtBlue]example/files/numbers/one two/[Reset])
2913";
2914        let files = create_files("", "/root", "");
2915        let files = modify_files_by_name(files);
2916        let config = Config::default()
2917            .with_sort_name(true)
2918            .with_only_path(true)
2919            .with_abs_path(false);
2920        assert_eq!(expected, wrap_files(&config, false, &files));
2921    }
2922
2923    #[test]
2924    #[cfg(windows)]
2925    fn test_prints_absolute_paths_sorted_by_name_on_windows() {
2926        let expected = "\
2927[LtGreen]alpha.sh[Reset] ([LtBlue]D:\\root\\example\\files\\colours\\[Reset])
2928blue.txt ([LtBlue]D:\\root\\example\\files\\colours\\[Reset])
2929[LtCyan]count.sh[Reset] ([LtBlue]D:\\root\\example\\files\\numbers\\[Reset]) -> [LtBlue]D:\\etc\\numbers\\[Reset][LtGreen]count.sh[Reset]
2930[DkGreen]find.sh[Reset] ([LtBlue]D:\\root\\example\\[Reset])
2931[LtCyan]googolplex.gz[Reset] ([LtBlue]D:\\root\\example\\files\\numbers\\[Reset]) -> [LtBlue]D:\\etc\\numbers\\[Reset][LtRed]googolplex.gz[Reset]
2932green.txt ([LtBlue]D:\\root\\example\\files\\colours\\[Reset])
2933[LtCyan]ordinals[Reset] ([LtBlue]D:\\root\\example\\files\\numbers\\[Reset]) -> [LtBlue]D:\\etc\\numbers\\[Reset][LtBlue]ordinals\\[Reset]
2934red.txt ([LtBlue]D:\\root\\example\\files\\colours\\[Reset])
2935\"three\" 'four'.txt ([LtBlue]D:\\root\\example\\files\\numbers\\one two\\[Reset])
2936";
2937        let files = create_files("D:", "/root", "");
2938        let files = modify_files_by_name(files);
2939        let config = Config::default()
2940            .with_sort_name(true)
2941            .with_only_path(true)
2942            .with_abs_path(true);
2943        assert_eq!(expected, wrap_files(&config, false, &files));
2944    }
2945
2946    #[test]
2947    #[cfg(windows)]
2948    fn test_prints_absolute_paths_sorted_by_name_on_git_bash() {
2949        let expected = "\
2950[LtGreen]alpha.sh[Reset] ([LtBlue]/d/root/example/files/colours/[Reset])
2951blue.txt ([LtBlue]/d/root/example/files/colours/[Reset])
2952[LtCyan]count.sh[Reset] ([LtBlue]/d/root/example/files/numbers/[Reset]) -> [LtBlue]/d/etc/numbers/[Reset][LtGreen]count.sh[Reset]
2953[DkGreen]find.sh[Reset] ([LtBlue]/d/root/example/[Reset])
2954[LtCyan]googolplex.gz[Reset] ([LtBlue]/d/root/example/files/numbers/[Reset]) -> [LtBlue]/d/etc/numbers/[Reset][LtRed]googolplex.gz[Reset]
2955green.txt ([LtBlue]/d/root/example/files/colours/[Reset])
2956[LtCyan]ordinals[Reset] ([LtBlue]/d/root/example/files/numbers/[Reset]) -> [LtBlue]/d/etc/numbers/[Reset][LtBlue]ordinals/[Reset]
2957red.txt ([LtBlue]/d/root/example/files/colours/[Reset])
2958\"three\" 'four'.txt ([LtBlue]/d/root/example/files/numbers/one two/[Reset])
2959";
2960        let files = create_files("D:", "/root", "");
2961        let files = modify_files_by_name(files);
2962        let config = Config::default()
2963            .with_sort_name(true)
2964            .with_only_path(true)
2965            .with_abs_path(true);
2966        assert_eq!(expected, wrap_files(&config, true, &files));
2967    }
2968
2969    #[test]
2970    #[cfg(not(windows))]
2971    fn test_prints_absolute_paths_sorted_by_name_on_linux() {
2972        let expected = "\
2973[LtGreen]alpha.sh[Reset] ([LtBlue]/root/example/files/colours/[Reset])
2974blue.txt ([LtBlue]/root/example/files/colours/[Reset])
2975[LtCyan]count.sh[Reset] ([LtBlue]/root/example/files/numbers/[Reset]) -> [LtBlue]/etc/numbers/[Reset][LtGreen]count.sh[Reset]
2976[DkGreen]find.sh[Reset] ([LtBlue]/root/example/[Reset])
2977[LtCyan]googolplex.gz[Reset] ([LtBlue]/root/example/files/numbers/[Reset]) -> [LtBlue]/etc/numbers/[Reset][LtRed]googolplex.gz[Reset]
2978green.txt ([LtBlue]/root/example/files/colours/[Reset])
2979[LtCyan]ordinals[Reset] ([LtBlue]/root/example/files/numbers/[Reset]) -> [LtBlue]/etc/numbers/[Reset][LtBlue]ordinals/[Reset]
2980red.txt ([LtBlue]/root/example/files/colours/[Reset])
2981\"three\" 'four'.txt ([LtBlue]/root/example/files/numbers/one two/[Reset])
2982";
2983        let files = create_files("", "/root", "");
2984        let files = modify_files_by_name(files);
2985        let config = Config::default()
2986            .with_sort_name(true)
2987            .with_only_path(true)
2988            .with_abs_path(true);
2989        assert_eq!(expected, wrap_files(&config, false, &files));
2990    }
2991
2992    #[test]
2993    #[cfg(windows)]
2994    fn test_prints_relative_paths_with_zip_sorted_by_name_on_windows() {
2995        let expected = "\
2996[LtGreen]alpha.sh[Reset] ([LtBlue]example\\[LtRed]files.zip[LtBlue]\\colours\\[Reset])
2997blue.txt ([LtBlue]example\\[LtRed]files.zip[LtBlue]\\colours\\[Reset])
2998[LtCyan]count.sh[Reset] ([LtBlue]example\\[LtRed]files.zip[LtBlue]\\numbers\\[Reset]) -> [LtBlue]D:\\etc\\numbers\\[Reset][LtGreen]count.sh[Reset]
2999[DkGreen]find.sh[Reset] ([LtBlue]example\\[Reset])
3000[LtCyan]googolplex.gz[Reset] ([LtBlue]example\\[LtRed]files.zip[LtBlue]\\numbers\\[Reset]) -> [LtBlue]D:\\etc\\numbers\\[Reset][LtRed]googolplex.gz[Reset]
3001green.txt ([LtBlue]example\\[LtRed]files.zip[LtBlue]\\colours\\[Reset])
3002[LtCyan]ordinals[Reset] ([LtBlue]example\\[LtRed]files.zip[LtBlue]\\numbers\\[Reset]) -> [LtBlue]D:\\etc\\numbers\\[Reset][LtBlue]ordinals\\[Reset]
3003red.txt ([LtBlue]example\\[LtRed]files.zip[LtBlue]\\colours\\[Reset])
3004\"three\" 'four'.txt ([LtBlue]example\\[LtRed]files.zip[LtBlue]\\numbers\\one two\\[Reset])
3005";
3006        let files = create_files("D:", "/root", "");
3007        let files = modify_files_by_name(files);
3008        let files = modify_files_for_zip(files);
3009        let config = Config::default()
3010            .with_zip_expand(true)
3011            .with_sort_name(true)
3012            .with_only_path(true)
3013            .with_abs_path(false);
3014        assert_eq!(expected, wrap_files(&config, false, &files));
3015    }
3016
3017    #[test]
3018    #[cfg(windows)]
3019    fn test_prints_relative_paths_with_zip_sorted_by_name_on_git_bash() {
3020        let expected = "\
3021[LtGreen]alpha.sh[Reset] ([LtBlue]example/[LtRed]files.zip[LtBlue]/colours/[Reset])
3022blue.txt ([LtBlue]example/[LtRed]files.zip[LtBlue]/colours/[Reset])
3023[LtCyan]count.sh[Reset] ([LtBlue]example/[LtRed]files.zip[LtBlue]/numbers/[Reset]) -> [LtBlue]/d/etc/numbers/[Reset][LtGreen]count.sh[Reset]
3024[DkGreen]find.sh[Reset] ([LtBlue]example/[Reset])
3025[LtCyan]googolplex.gz[Reset] ([LtBlue]example/[LtRed]files.zip[LtBlue]/numbers/[Reset]) -> [LtBlue]/d/etc/numbers/[Reset][LtRed]googolplex.gz[Reset]
3026green.txt ([LtBlue]example/[LtRed]files.zip[LtBlue]/colours/[Reset])
3027[LtCyan]ordinals[Reset] ([LtBlue]example/[LtRed]files.zip[LtBlue]/numbers/[Reset]) -> [LtBlue]/d/etc/numbers/[Reset][LtBlue]ordinals/[Reset]
3028red.txt ([LtBlue]example/[LtRed]files.zip[LtBlue]/colours/[Reset])
3029\"three\" 'four'.txt ([LtBlue]example/[LtRed]files.zip[LtBlue]/numbers/one two/[Reset])
3030";
3031        let files = create_files("D:", "/root", "");
3032        let files = modify_files_by_name(files);
3033        let files = modify_files_for_zip(files);
3034        let config = Config::default()
3035            .with_zip_expand(true)
3036            .with_sort_name(true)
3037            .with_only_path(true)
3038            .with_abs_path(false);
3039        assert_eq!(expected, wrap_files(&config, true, &files));
3040    }
3041
3042    #[test]
3043    #[cfg(not(windows))]
3044    fn test_prints_relative_paths_with_zip_sorted_by_name_on_linux() {
3045        let expected = "\
3046[LtGreen]alpha.sh[Reset] ([LtBlue]example/[LtRed]files.zip[LtBlue]/colours/[Reset])
3047blue.txt ([LtBlue]example/[LtRed]files.zip[LtBlue]/colours/[Reset])
3048[LtCyan]count.sh[Reset] ([LtBlue]example/[LtRed]files.zip[LtBlue]/numbers/[Reset]) -> [LtBlue]/etc/numbers/[Reset][LtGreen]count.sh[Reset]
3049[DkGreen]find.sh[Reset] ([LtBlue]example/[Reset])
3050[LtCyan]googolplex.gz[Reset] ([LtBlue]example/[LtRed]files.zip[LtBlue]/numbers/[Reset]) -> [LtBlue]/etc/numbers/[Reset][LtRed]googolplex.gz[Reset]
3051green.txt ([LtBlue]example/[LtRed]files.zip[LtBlue]/colours/[Reset])
3052[LtCyan]ordinals[Reset] ([LtBlue]example/[LtRed]files.zip[LtBlue]/numbers/[Reset]) -> [LtBlue]/etc/numbers/[Reset][LtBlue]ordinals/[Reset]
3053red.txt ([LtBlue]example/[LtRed]files.zip[LtBlue]/colours/[Reset])
3054\"three\" 'four'.txt ([LtBlue]example/[LtRed]files.zip[LtBlue]/numbers/one two/[Reset])
3055";
3056        let files = create_files("", "/root", "");
3057        let files = modify_files_by_name(files);
3058        let files = modify_files_for_zip(files);
3059        let config = Config::default()
3060            .with_zip_expand(true)
3061            .with_sort_name(true)
3062            .with_only_path(true)
3063            .with_abs_path(false);
3064        assert_eq!(expected, wrap_files(&config, false, &files));
3065    }
3066
3067    #[test]
3068    #[cfg(windows)]
3069    fn test_prints_absolute_paths_with_zip_sorted_by_name_on_windows() {
3070        let expected = "\
3071[LtGreen]alpha.sh[Reset] ([LtBlue]D:\\root\\example\\[LtRed]files.zip[LtBlue]\\colours\\[Reset])
3072blue.txt ([LtBlue]D:\\root\\example\\[LtRed]files.zip[LtBlue]\\colours\\[Reset])
3073[LtCyan]count.sh[Reset] ([LtBlue]D:\\root\\example\\[LtRed]files.zip[LtBlue]\\numbers\\[Reset]) -> [LtBlue]D:\\etc\\numbers\\[Reset][LtGreen]count.sh[Reset]
3074[DkGreen]find.sh[Reset] ([LtBlue]D:\\root\\example\\[Reset])
3075[LtCyan]googolplex.gz[Reset] ([LtBlue]D:\\root\\example\\[LtRed]files.zip[LtBlue]\\numbers\\[Reset]) -> [LtBlue]D:\\etc\\numbers\\[Reset][LtRed]googolplex.gz[Reset]
3076green.txt ([LtBlue]D:\\root\\example\\[LtRed]files.zip[LtBlue]\\colours\\[Reset])
3077[LtCyan]ordinals[Reset] ([LtBlue]D:\\root\\example\\[LtRed]files.zip[LtBlue]\\numbers\\[Reset]) -> [LtBlue]D:\\etc\\numbers\\[Reset][LtBlue]ordinals\\[Reset]
3078red.txt ([LtBlue]D:\\root\\example\\[LtRed]files.zip[LtBlue]\\colours\\[Reset])
3079\"three\" 'four'.txt ([LtBlue]D:\\root\\example\\[LtRed]files.zip[LtBlue]\\numbers\\one two\\[Reset])
3080";
3081        let files = create_files("D:", "/root", "");
3082        let files = modify_files_by_name(files);
3083        let files = modify_files_for_zip(files);
3084        let config = Config::default()
3085            .with_zip_expand(true)
3086            .with_sort_name(true)
3087            .with_only_path(true)
3088            .with_abs_path(true);
3089        assert_eq!(expected, wrap_files(&config, false, &files));
3090    }
3091
3092    #[test]
3093    #[cfg(windows)]
3094    fn test_prints_absolute_paths_with_zip_sorted_by_name_on_git_bash() {
3095        let expected = "\
3096[LtGreen]alpha.sh[Reset] ([LtBlue]/d/root/example/[LtRed]files.zip[LtBlue]/colours/[Reset])
3097blue.txt ([LtBlue]/d/root/example/[LtRed]files.zip[LtBlue]/colours/[Reset])
3098[LtCyan]count.sh[Reset] ([LtBlue]/d/root/example/[LtRed]files.zip[LtBlue]/numbers/[Reset]) -> [LtBlue]/d/etc/numbers/[Reset][LtGreen]count.sh[Reset]
3099[DkGreen]find.sh[Reset] ([LtBlue]/d/root/example/[Reset])
3100[LtCyan]googolplex.gz[Reset] ([LtBlue]/d/root/example/[LtRed]files.zip[LtBlue]/numbers/[Reset]) -> [LtBlue]/d/etc/numbers/[Reset][LtRed]googolplex.gz[Reset]
3101green.txt ([LtBlue]/d/root/example/[LtRed]files.zip[LtBlue]/colours/[Reset])
3102[LtCyan]ordinals[Reset] ([LtBlue]/d/root/example/[LtRed]files.zip[LtBlue]/numbers/[Reset]) -> [LtBlue]/d/etc/numbers/[Reset][LtBlue]ordinals/[Reset]
3103red.txt ([LtBlue]/d/root/example/[LtRed]files.zip[LtBlue]/colours/[Reset])
3104\"three\" 'four'.txt ([LtBlue]/d/root/example/[LtRed]files.zip[LtBlue]/numbers/one two/[Reset])
3105";
3106        let files = create_files("D:", "/root", "");
3107        let files = modify_files_by_name(files);
3108        let files = modify_files_for_zip(files);
3109        let config = Config::default()
3110            .with_zip_expand(true)
3111            .with_sort_name(true)
3112            .with_only_path(true)
3113            .with_abs_path(true);
3114        assert_eq!(expected, wrap_files(&config, true, &files));
3115    }
3116
3117    #[test]
3118    #[cfg(not(windows))]
3119    fn test_prints_absolute_paths_with_zip_sorted_by_name_on_linux() {
3120        let expected = "\
3121[LtGreen]alpha.sh[Reset] ([LtBlue]/root/example/[LtRed]files.zip[LtBlue]/colours/[Reset])
3122blue.txt ([LtBlue]/root/example/[LtRed]files.zip[LtBlue]/colours/[Reset])
3123[LtCyan]count.sh[Reset] ([LtBlue]/root/example/[LtRed]files.zip[LtBlue]/numbers/[Reset]) -> [LtBlue]/etc/numbers/[Reset][LtGreen]count.sh[Reset]
3124[DkGreen]find.sh[Reset] ([LtBlue]/root/example/[Reset])
3125[LtCyan]googolplex.gz[Reset] ([LtBlue]/root/example/[LtRed]files.zip[LtBlue]/numbers/[Reset]) -> [LtBlue]/etc/numbers/[Reset][LtRed]googolplex.gz[Reset]
3126green.txt ([LtBlue]/root/example/[LtRed]files.zip[LtBlue]/colours/[Reset])
3127[LtCyan]ordinals[Reset] ([LtBlue]/root/example/[LtRed]files.zip[LtBlue]/numbers/[Reset]) -> [LtBlue]/etc/numbers/[Reset][LtBlue]ordinals/[Reset]
3128red.txt ([LtBlue]/root/example/[LtRed]files.zip[LtBlue]/colours/[Reset])
3129\"three\" 'four'.txt ([LtBlue]/root/example/[LtRed]files.zip[LtBlue]/numbers/one two/[Reset])
3130";
3131        let files = create_files("", "/root", "");
3132        let files = modify_files_by_name(files);
3133        let files = modify_files_for_zip(files);
3134        let config = Config::default()
3135            .with_zip_expand(true)
3136            .with_sort_name(true)
3137            .with_only_path(true)
3138            .with_abs_path(true);
3139        assert_eq!(expected, wrap_files(&config, false, &files));
3140    }
3141
3142    #[test]
3143    #[cfg(windows)]
3144    fn test_prints_indented_paths_with_attributes_on_windows() {
3145        let expected = "\
3146drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example[Reset]
3147-rwxr-xr-x   10  Wed 01-Nov-2023 00:00:00  .sh    [LtBlue]+-[Reset] [DkGreen]find.sh[Reset]
3148drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00         [LtBlue]\\-[Reset] [LtBlue]files[Reset]
3149drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00             [LtBlue]+-[Reset] [LtBlue]colours[Reset]
3150-rwxr--r--   20  Sun 01-Oct-2023 00:00:00  .sh        [LtBlue]|[Reset]   [LtBlue]+-[Reset] [LtGreen]alpha.sh[Reset]
3151-rw-r--r--   30  Fri 01-Sep-2023 00:00:00  .txt       [LtBlue]|[Reset]   [LtBlue]+-[Reset] blue.txt
3152-rw-r--r--   40  Tue 01-Aug-2023 00:00:00  .txt       [LtBlue]|[Reset]   [LtBlue]+-[Reset] green.txt
3153-rw-r--r--   50  Sat 01-Jul-2023 00:00:00  .txt       [LtBlue]|[Reset]   [LtBlue]\\-[Reset] red.txt
3154drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00             [LtBlue]\\-[Reset] [LtBlue]numbers[Reset]
3155lrwxr--r--   60  Thu 01-Jun-2023 00:00:00  .sh            [LtBlue]+-[Reset] [LtCyan]count.sh[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtGreen]count.sh[Reset]
3156lrw-r--r--  999  Mon 01-May-2023 00:00:00  .gz            [LtBlue]+-[Reset] [LtCyan]googolplex.gz[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtRed]googolplex.gz[Reset]
3157lrw-r--r--    0  Sat 01-Apr-2023 00:00:00                 [LtBlue]+-[Reset] [LtCyan]ordinals[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtBlue]ordinals\\[Reset]
3158drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00                 [LtBlue]\\-[Reset] [LtBlue]one two[Reset]
3159-rw-r--r--   70  Wed 01-Mar-2023 00:00:00  .txt               [LtBlue]\\-[Reset] \"three\" 'four'.txt
3160";
3161        let files = create_files("D:", "/root", "../..");
3162        let config = Config::default()
3163            .with_show_precise(true)
3164            .with_show_indent(true)
3165            .with_only_path(false)
3166            .with_abs_path(true);
3167        assert_eq!(expected, wrap_files(&config, false, &files));
3168    }
3169
3170    #[test]
3171    #[cfg(windows)]
3172    fn test_prints_indented_paths_with_attributes_on_git_bash() {
3173        let expected = "\
3174drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example[Reset]
3175-rwxr-xr-x   10  Wed 01-Nov-2023 00:00:00  .sh    [LtBlue]+-[Reset] [DkGreen]find.sh[Reset]
3176drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00         [LtBlue]\\-[Reset] [LtBlue]files[Reset]
3177drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00             [LtBlue]+-[Reset] [LtBlue]colours[Reset]
3178-rwxr--r--   20  Sun 01-Oct-2023 00:00:00  .sh        [LtBlue]|[Reset]   [LtBlue]+-[Reset] [LtGreen]alpha.sh[Reset]
3179-rw-r--r--   30  Fri 01-Sep-2023 00:00:00  .txt       [LtBlue]|[Reset]   [LtBlue]+-[Reset] blue.txt
3180-rw-r--r--   40  Tue 01-Aug-2023 00:00:00  .txt       [LtBlue]|[Reset]   [LtBlue]+-[Reset] green.txt
3181-rw-r--r--   50  Sat 01-Jul-2023 00:00:00  .txt       [LtBlue]|[Reset]   [LtBlue]\\-[Reset] red.txt
3182drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00             [LtBlue]\\-[Reset] [LtBlue]numbers[Reset]
3183lrwxr--r--   60  Thu 01-Jun-2023 00:00:00  .sh            [LtBlue]+-[Reset] [LtCyan]count.sh[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtGreen]count.sh[Reset]
3184lrw-r--r--  999  Mon 01-May-2023 00:00:00  .gz            [LtBlue]+-[Reset] [LtCyan]googolplex.gz[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtRed]googolplex.gz[Reset]
3185lrw-r--r--    0  Sat 01-Apr-2023 00:00:00                 [LtBlue]+-[Reset] [LtCyan]ordinals[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtBlue]ordinals/[Reset]
3186drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00                 [LtBlue]\\-[Reset] [LtBlue]one two[Reset]
3187-rw-r--r--   70  Wed 01-Mar-2023 00:00:00  .txt               [LtBlue]\\-[Reset] \"three\" 'four'.txt
3188";
3189        let files = create_files("D:", "/root", "../..");
3190        let config = Config::default()
3191            .with_show_precise(true)
3192            .with_show_indent(true)
3193            .with_only_path(false)
3194            .with_abs_path(true);
3195        assert_eq!(expected, wrap_files(&config, true, &files));
3196    }
3197
3198    #[test]
3199    #[cfg(not(windows))]
3200    fn test_prints_indented_paths_with_attributes_on_linux() {
3201        let expected = "\
3202drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example[Reset]
3203-rwxr-xr-x   10  Wed 01-Nov-2023 00:00:00  .sh    [LtBlue]+-[Reset] [DkGreen]find.sh[Reset]
3204drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00         [LtBlue]\\-[Reset] [LtBlue]files[Reset]
3205drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00             [LtBlue]+-[Reset] [LtBlue]colours[Reset]
3206-rwxr--r--   20  Sun 01-Oct-2023 00:00:00  .sh        [LtBlue]|[Reset]   [LtBlue]+-[Reset] [LtGreen]alpha.sh[Reset]
3207-rw-r--r--   30  Fri 01-Sep-2023 00:00:00  .txt       [LtBlue]|[Reset]   [LtBlue]+-[Reset] blue.txt
3208-rw-r--r--   40  Tue 01-Aug-2023 00:00:00  .txt       [LtBlue]|[Reset]   [LtBlue]+-[Reset] green.txt
3209-rw-r--r--   50  Sat 01-Jul-2023 00:00:00  .txt       [LtBlue]|[Reset]   [LtBlue]\\-[Reset] red.txt
3210drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00             [LtBlue]\\-[Reset] [LtBlue]numbers[Reset]
3211lrwxr--r--   60  Thu 01-Jun-2023 00:00:00  .sh            [LtBlue]+-[Reset] [LtCyan]count.sh[Reset] -> [LtBlue]/etc/numbers/[Reset][LtGreen]count.sh[Reset]
3212lrw-r--r--  999  Mon 01-May-2023 00:00:00  .gz            [LtBlue]+-[Reset] [LtCyan]googolplex.gz[Reset] -> [LtBlue]/etc/numbers/[Reset][LtRed]googolplex.gz[Reset]
3213lrw-r--r--    0  Sat 01-Apr-2023 00:00:00                 [LtBlue]+-[Reset] [LtCyan]ordinals[Reset] -> [LtBlue]/etc/numbers/[Reset][LtBlue]ordinals/[Reset]
3214drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00                 [LtBlue]\\-[Reset] [LtBlue]one two[Reset]
3215-rw-r--r--   70  Wed 01-Mar-2023 00:00:00  .txt               [LtBlue]\\-[Reset] \"three\" 'four'.txt
3216";
3217        let files = create_files("", "/root", "../..");
3218        let config = Config::default()
3219            .with_show_precise(true)
3220            .with_show_indent(true)
3221            .with_only_path(false)
3222            .with_abs_path(true);
3223        assert_eq!(expected, wrap_files(&config, false, &files));
3224    }
3225
3226    #[test]
3227    #[cfg(windows)]
3228    fn test_prints_indented_paths_no_attributes_on_windows() {
3229        let expected = "\
3230[LtBlue]example[Reset]
3231 [LtBlue]+-[Reset] [DkGreen]find.sh[Reset]
3232 [LtBlue]\\-[Reset] [LtBlue]files[Reset]
3233     [LtBlue]+-[Reset] [LtBlue]colours[Reset]
3234     [LtBlue]|[Reset]   [LtBlue]+-[Reset] [LtGreen]alpha.sh[Reset]
3235     [LtBlue]|[Reset]   [LtBlue]+-[Reset] blue.txt
3236     [LtBlue]|[Reset]   [LtBlue]+-[Reset] green.txt
3237     [LtBlue]|[Reset]   [LtBlue]\\-[Reset] red.txt
3238     [LtBlue]\\-[Reset] [LtBlue]numbers[Reset]
3239         [LtBlue]+-[Reset] [LtCyan]count.sh[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtGreen]count.sh[Reset]
3240         [LtBlue]+-[Reset] [LtCyan]googolplex.gz[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtRed]googolplex.gz[Reset]
3241         [LtBlue]+-[Reset] [LtCyan]ordinals[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtBlue]ordinals\\[Reset]
3242         [LtBlue]\\-[Reset] [LtBlue]one two[Reset]
3243             [LtBlue]\\-[Reset] \"three\" 'four'.txt
3244";
3245        let files = create_files("D:", "/root", "../..");
3246        let config = Config::default()
3247            .with_show_indent(true)
3248            .with_only_path(true)
3249            .with_abs_path(true);
3250        assert_eq!(expected, wrap_files(&config, false, &files));
3251    }
3252
3253    #[test]
3254    #[cfg(windows)]
3255    fn test_prints_indented_paths_no_attributes_on_git_bash() {
3256        let expected = "\
3257[LtBlue]example[Reset]
3258 [LtBlue]+-[Reset] [DkGreen]find.sh[Reset]
3259 [LtBlue]\\-[Reset] [LtBlue]files[Reset]
3260     [LtBlue]+-[Reset] [LtBlue]colours[Reset]
3261     [LtBlue]|[Reset]   [LtBlue]+-[Reset] [LtGreen]alpha.sh[Reset]
3262     [LtBlue]|[Reset]   [LtBlue]+-[Reset] blue.txt
3263     [LtBlue]|[Reset]   [LtBlue]+-[Reset] green.txt
3264     [LtBlue]|[Reset]   [LtBlue]\\-[Reset] red.txt
3265     [LtBlue]\\-[Reset] [LtBlue]numbers[Reset]
3266         [LtBlue]+-[Reset] [LtCyan]count.sh[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtGreen]count.sh[Reset]
3267         [LtBlue]+-[Reset] [LtCyan]googolplex.gz[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtRed]googolplex.gz[Reset]
3268         [LtBlue]+-[Reset] [LtCyan]ordinals[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtBlue]ordinals/[Reset]
3269         [LtBlue]\\-[Reset] [LtBlue]one two[Reset]
3270             [LtBlue]\\-[Reset] \"three\" 'four'.txt
3271";
3272        let files = create_files("D:", "/root", "../..");
3273        let config = Config::default()
3274            .with_show_indent(true)
3275            .with_only_path(true)
3276            .with_abs_path(true);
3277        assert_eq!(expected, wrap_files(&config, true, &files));
3278    }
3279
3280    #[test]
3281    #[cfg(not(windows))]
3282    fn test_prints_indented_paths_no_attributes_on_linux() {
3283        let expected = "\
3284[LtBlue]example[Reset]
3285 [LtBlue]+-[Reset] [DkGreen]find.sh[Reset]
3286 [LtBlue]\\-[Reset] [LtBlue]files[Reset]
3287     [LtBlue]+-[Reset] [LtBlue]colours[Reset]
3288     [LtBlue]|[Reset]   [LtBlue]+-[Reset] [LtGreen]alpha.sh[Reset]
3289     [LtBlue]|[Reset]   [LtBlue]+-[Reset] blue.txt
3290     [LtBlue]|[Reset]   [LtBlue]+-[Reset] green.txt
3291     [LtBlue]|[Reset]   [LtBlue]\\-[Reset] red.txt
3292     [LtBlue]\\-[Reset] [LtBlue]numbers[Reset]
3293         [LtBlue]+-[Reset] [LtCyan]count.sh[Reset] -> [LtBlue]/etc/numbers/[Reset][LtGreen]count.sh[Reset]
3294         [LtBlue]+-[Reset] [LtCyan]googolplex.gz[Reset] -> [LtBlue]/etc/numbers/[Reset][LtRed]googolplex.gz[Reset]
3295         [LtBlue]+-[Reset] [LtCyan]ordinals[Reset] -> [LtBlue]/etc/numbers/[Reset][LtBlue]ordinals/[Reset]
3296         [LtBlue]\\-[Reset] [LtBlue]one two[Reset]
3297             [LtBlue]\\-[Reset] \"three\" 'four'.txt
3298";
3299        let files = create_files("", "/root", "../..");
3300        let config = Config::default()
3301            .with_show_indent(true)
3302            .with_only_path(true)
3303            .with_abs_path(true);
3304        assert_eq!(expected, wrap_files(&config, false, &files));
3305    }
3306
3307    #[test]
3308    #[cfg(windows)]
3309    fn test_prints_indented_paths_with_zip_with_attributes_on_windows() {
3310        let expected = "\
3311-drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example[Reset]
3312--rwxr-xr-x   10  Wed 01-Nov-2023 00:00:00  .sh    [LtBlue]+-[Reset] [DkGreen]find.sh[Reset]
3313zdrwxr-xr-x    0  Sun 31-Dec-2023 00:00:00         [LtBlue]\\-[Reset] [LtRed]files.zip[Reset]
3314zdrwxr-xr-x    0  Sun 31-Dec-2023 00:00:00             [LtBlue]+-[Reset] [LtBlue]colours[Reset]
3315z-rwxr--r--   20  Sun 01-Oct-2023 00:00:00  .sh        [LtBlue]|[Reset]   [LtBlue]+-[Reset] [LtGreen]alpha.sh[Reset]
3316z-rw-r--r--   30  Fri 01-Sep-2023 00:00:00  .txt       [LtBlue]|[Reset]   [LtBlue]+-[Reset] blue.txt
3317z-rw-r--r--   40  Tue 01-Aug-2023 00:00:00  .txt       [LtBlue]|[Reset]   [LtBlue]+-[Reset] green.txt
3318z-rw-r--r--   50  Sat 01-Jul-2023 00:00:00  .txt       [LtBlue]|[Reset]   [LtBlue]\\-[Reset] red.txt
3319zdrwxr-xr-x    0  Sun 31-Dec-2023 00:00:00             [LtBlue]\\-[Reset] [LtBlue]numbers[Reset]
3320zlrwxr--r--   60  Thu 01-Jun-2023 00:00:00  .sh            [LtBlue]+-[Reset] [LtCyan]count.sh[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtGreen]count.sh[Reset]
3321zlrw-r--r--  999  Mon 01-May-2023 00:00:00  .gz            [LtBlue]+-[Reset] [LtCyan]googolplex.gz[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtRed]googolplex.gz[Reset]
3322zlrw-r--r--    0  Sat 01-Apr-2023 00:00:00                 [LtBlue]+-[Reset] [LtCyan]ordinals[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtBlue]ordinals\\[Reset]
3323zdrwxr-xr-x    0  Sun 31-Dec-2023 00:00:00                 [LtBlue]\\-[Reset] [LtBlue]one two[Reset]
3324z-rw-r--r--   70  Wed 01-Mar-2023 00:00:00  .txt               [LtBlue]\\-[Reset] \"three\" 'four'.txt
3325";
3326        let files = create_files("D:", "/root", "../..");
3327        let files = modify_files_for_zip(files);
3328        let config = Config::default()
3329            .with_zip_expand(true)
3330            .with_show_precise(true)
3331            .with_show_indent(true)
3332            .with_only_path(false)
3333            .with_abs_path(true);
3334        assert_eq!(expected, wrap_files(&config, false, &files));
3335    }
3336
3337    #[test]
3338    #[cfg(windows)]
3339    fn test_prints_indented_paths_with_zip_with_attributes_on_git_bash() {
3340        let expected = "\
3341-drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example[Reset]
3342--rwxr-xr-x   10  Wed 01-Nov-2023 00:00:00  .sh    [LtBlue]+-[Reset] [DkGreen]find.sh[Reset]
3343zdrwxr-xr-x    0  Sun 31-Dec-2023 00:00:00         [LtBlue]\\-[Reset] [LtRed]files.zip[Reset]
3344zdrwxr-xr-x    0  Sun 31-Dec-2023 00:00:00             [LtBlue]+-[Reset] [LtBlue]colours[Reset]
3345z-rwxr--r--   20  Sun 01-Oct-2023 00:00:00  .sh        [LtBlue]|[Reset]   [LtBlue]+-[Reset] [LtGreen]alpha.sh[Reset]
3346z-rw-r--r--   30  Fri 01-Sep-2023 00:00:00  .txt       [LtBlue]|[Reset]   [LtBlue]+-[Reset] blue.txt
3347z-rw-r--r--   40  Tue 01-Aug-2023 00:00:00  .txt       [LtBlue]|[Reset]   [LtBlue]+-[Reset] green.txt
3348z-rw-r--r--   50  Sat 01-Jul-2023 00:00:00  .txt       [LtBlue]|[Reset]   [LtBlue]\\-[Reset] red.txt
3349zdrwxr-xr-x    0  Sun 31-Dec-2023 00:00:00             [LtBlue]\\-[Reset] [LtBlue]numbers[Reset]
3350zlrwxr--r--   60  Thu 01-Jun-2023 00:00:00  .sh            [LtBlue]+-[Reset] [LtCyan]count.sh[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtGreen]count.sh[Reset]
3351zlrw-r--r--  999  Mon 01-May-2023 00:00:00  .gz            [LtBlue]+-[Reset] [LtCyan]googolplex.gz[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtRed]googolplex.gz[Reset]
3352zlrw-r--r--    0  Sat 01-Apr-2023 00:00:00                 [LtBlue]+-[Reset] [LtCyan]ordinals[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtBlue]ordinals/[Reset]
3353zdrwxr-xr-x    0  Sun 31-Dec-2023 00:00:00                 [LtBlue]\\-[Reset] [LtBlue]one two[Reset]
3354z-rw-r--r--   70  Wed 01-Mar-2023 00:00:00  .txt               [LtBlue]\\-[Reset] \"three\" 'four'.txt
3355";
3356        let files = create_files("D:", "/root", "../..");
3357        let files = modify_files_for_zip(files);
3358        let config = Config::default()
3359            .with_zip_expand(true)
3360            .with_show_precise(true)
3361            .with_show_indent(true)
3362            .with_only_path(false)
3363            .with_abs_path(true);
3364        assert_eq!(expected, wrap_files(&config, true, &files));
3365    }
3366
3367    #[test]
3368    #[cfg(not(windows))]
3369    fn test_prints_indented_paths_with_zip_with_attributes_on_linux() {
3370        let expected = "\
3371-drwxr-xr-x    0  Sun 31-Dec-2023 00:00:00        [LtBlue]example[Reset]
3372--rwxr-xr-x   10  Wed 01-Nov-2023 00:00:00  .sh    [LtBlue]+-[Reset] [DkGreen]find.sh[Reset]
3373zdrwxr-xr-x    0  Sun 31-Dec-2023 00:00:00         [LtBlue]\\-[Reset] [LtRed]files.zip[Reset]
3374zdrwxr-xr-x    0  Sun 31-Dec-2023 00:00:00             [LtBlue]+-[Reset] [LtBlue]colours[Reset]
3375z-rwxr--r--   20  Sun 01-Oct-2023 00:00:00  .sh        [LtBlue]|[Reset]   [LtBlue]+-[Reset] [LtGreen]alpha.sh[Reset]
3376z-rw-r--r--   30  Fri 01-Sep-2023 00:00:00  .txt       [LtBlue]|[Reset]   [LtBlue]+-[Reset] blue.txt
3377z-rw-r--r--   40  Tue 01-Aug-2023 00:00:00  .txt       [LtBlue]|[Reset]   [LtBlue]+-[Reset] green.txt
3378z-rw-r--r--   50  Sat 01-Jul-2023 00:00:00  .txt       [LtBlue]|[Reset]   [LtBlue]\\-[Reset] red.txt
3379zdrwxr-xr-x    0  Sun 31-Dec-2023 00:00:00             [LtBlue]\\-[Reset] [LtBlue]numbers[Reset]
3380zlrwxr--r--   60  Thu 01-Jun-2023 00:00:00  .sh            [LtBlue]+-[Reset] [LtCyan]count.sh[Reset] -> [LtBlue]/etc/numbers/[Reset][LtGreen]count.sh[Reset]
3381zlrw-r--r--  999  Mon 01-May-2023 00:00:00  .gz            [LtBlue]+-[Reset] [LtCyan]googolplex.gz[Reset] -> [LtBlue]/etc/numbers/[Reset][LtRed]googolplex.gz[Reset]
3382zlrw-r--r--    0  Sat 01-Apr-2023 00:00:00                 [LtBlue]+-[Reset] [LtCyan]ordinals[Reset] -> [LtBlue]/etc/numbers/[Reset][LtBlue]ordinals/[Reset]
3383zdrwxr-xr-x    0  Sun 31-Dec-2023 00:00:00                 [LtBlue]\\-[Reset] [LtBlue]one two[Reset]
3384z-rw-r--r--   70  Wed 01-Mar-2023 00:00:00  .txt               [LtBlue]\\-[Reset] \"three\" 'four'.txt
3385";
3386        let files = create_files("", "/root", "../..");
3387        let files = modify_files_for_zip(files);
3388        let config = Config::default()
3389            .with_zip_expand(true)
3390            .with_show_precise(true)
3391            .with_show_indent(true)
3392            .with_only_path(false)
3393            .with_abs_path(true);
3394        assert_eq!(expected, wrap_files(&config, false, &files));
3395    }
3396
3397    #[test]
3398    #[cfg(windows)]
3399    fn test_prints_indented_paths_with_zip_no_attributes_on_windows() {
3400        let expected = "\
3401[LtBlue]example[Reset]
3402 [LtBlue]+-[Reset] [DkGreen]find.sh[Reset]
3403 [LtBlue]\\-[Reset] [LtRed]files.zip[Reset]
3404     [LtBlue]+-[Reset] [LtBlue]colours[Reset]
3405     [LtBlue]|[Reset]   [LtBlue]+-[Reset] [LtGreen]alpha.sh[Reset]
3406     [LtBlue]|[Reset]   [LtBlue]+-[Reset] blue.txt
3407     [LtBlue]|[Reset]   [LtBlue]+-[Reset] green.txt
3408     [LtBlue]|[Reset]   [LtBlue]\\-[Reset] red.txt
3409     [LtBlue]\\-[Reset] [LtBlue]numbers[Reset]
3410         [LtBlue]+-[Reset] [LtCyan]count.sh[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtGreen]count.sh[Reset]
3411         [LtBlue]+-[Reset] [LtCyan]googolplex.gz[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtRed]googolplex.gz[Reset]
3412         [LtBlue]+-[Reset] [LtCyan]ordinals[Reset] -> [LtBlue]D:\\etc\\numbers\\[Reset][LtBlue]ordinals\\[Reset]
3413         [LtBlue]\\-[Reset] [LtBlue]one two[Reset]
3414             [LtBlue]\\-[Reset] \"three\" 'four'.txt
3415";
3416        let files = create_files("D:", "/root", "../..");
3417        let files = modify_files_for_zip(files);
3418        let config = Config::default()
3419            .with_zip_expand(true)
3420            .with_show_indent(true)
3421            .with_only_path(true)
3422            .with_abs_path(true);
3423        assert_eq!(expected, wrap_files(&config, false, &files));
3424    }
3425
3426    #[test]
3427    #[cfg(windows)]
3428    fn test_prints_indented_paths_with_zip_no_attributes_on_git_bash() {
3429        let expected = "\
3430[LtBlue]example[Reset]
3431 [LtBlue]+-[Reset] [DkGreen]find.sh[Reset]
3432 [LtBlue]\\-[Reset] [LtRed]files.zip[Reset]
3433     [LtBlue]+-[Reset] [LtBlue]colours[Reset]
3434     [LtBlue]|[Reset]   [LtBlue]+-[Reset] [LtGreen]alpha.sh[Reset]
3435     [LtBlue]|[Reset]   [LtBlue]+-[Reset] blue.txt
3436     [LtBlue]|[Reset]   [LtBlue]+-[Reset] green.txt
3437     [LtBlue]|[Reset]   [LtBlue]\\-[Reset] red.txt
3438     [LtBlue]\\-[Reset] [LtBlue]numbers[Reset]
3439         [LtBlue]+-[Reset] [LtCyan]count.sh[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtGreen]count.sh[Reset]
3440         [LtBlue]+-[Reset] [LtCyan]googolplex.gz[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtRed]googolplex.gz[Reset]
3441         [LtBlue]+-[Reset] [LtCyan]ordinals[Reset] -> [LtBlue]/d/etc/numbers/[Reset][LtBlue]ordinals/[Reset]
3442         [LtBlue]\\-[Reset] [LtBlue]one two[Reset]
3443             [LtBlue]\\-[Reset] \"three\" 'four'.txt
3444";
3445        let files = create_files("D:", "/root", "../..");
3446        let files = modify_files_for_zip(files);
3447        let config = Config::default()
3448            .with_zip_expand(true)
3449            .with_show_indent(true)
3450            .with_only_path(true)
3451            .with_abs_path(true);
3452        assert_eq!(expected, wrap_files(&config, true, &files));
3453    }
3454
3455    #[test]
3456    #[cfg(not(windows))]
3457    fn test_prints_indented_paths_with_zip_no_attributes_on_linux() {
3458        let expected = "\
3459[LtBlue]example[Reset]
3460 [LtBlue]+-[Reset] [DkGreen]find.sh[Reset]
3461 [LtBlue]\\-[Reset] [LtRed]files.zip[Reset]
3462     [LtBlue]+-[Reset] [LtBlue]colours[Reset]
3463     [LtBlue]|[Reset]   [LtBlue]+-[Reset] [LtGreen]alpha.sh[Reset]
3464     [LtBlue]|[Reset]   [LtBlue]+-[Reset] blue.txt
3465     [LtBlue]|[Reset]   [LtBlue]+-[Reset] green.txt
3466     [LtBlue]|[Reset]   [LtBlue]\\-[Reset] red.txt
3467     [LtBlue]\\-[Reset] [LtBlue]numbers[Reset]
3468         [LtBlue]+-[Reset] [LtCyan]count.sh[Reset] -> [LtBlue]/etc/numbers/[Reset][LtGreen]count.sh[Reset]
3469         [LtBlue]+-[Reset] [LtCyan]googolplex.gz[Reset] -> [LtBlue]/etc/numbers/[Reset][LtRed]googolplex.gz[Reset]
3470         [LtBlue]+-[Reset] [LtCyan]ordinals[Reset] -> [LtBlue]/etc/numbers/[Reset][LtBlue]ordinals/[Reset]
3471         [LtBlue]\\-[Reset] [LtBlue]one two[Reset]
3472             [LtBlue]\\-[Reset] \"three\" 'four'.txt
3473";
3474        let files = create_files("", "/root", "../..");
3475        let files = modify_files_for_zip(files);
3476        let config = Config::default()
3477            .with_zip_expand(true)
3478            .with_show_indent(true)
3479            .with_only_path(true)
3480            .with_abs_path(true);
3481        assert_eq!(expected, wrap_files(&config, false, &files));
3482    }
3483
3484    fn wrap_mode(
3485        zip_expand: bool,
3486        inner_depth: Option<usize>,
3487        file_mode: u32,
3488        file_type: FileKind,
3489    ) -> String {
3490        let config = Config::default().with_zip_expand(zip_expand);
3491        wrap_function(&config, false, |p| p.print_mode(file_type, file_mode, inner_depth))
3492    }
3493
3494    fn wrap_size(config: &Config, file_size: u64, size_width: usize) -> String {
3495        wrap_function(config, false, |p| p.print_size(file_size, size_width))
3496    }
3497
3498    fn wrap_time(
3499        config: &Config,
3500        year: i32,
3501        month: u32,
3502        day: u32,
3503        hour: u32,
3504        minute: u32,
3505        second: u32,
3506    ) -> String {
3507        let time = Utc.with_ymd_and_hms(year, month, day, hour, minute, second).unwrap();
3508        wrap_function(config, false, |p| p.print_time(&time, &Utc, true))
3509    }
3510
3511    #[cfg(windows)]
3512    fn wrap_version(file_ver: Option<&str>, ver_width: usize) -> String {
3513        let config = Config::default();
3514        let file_ver = file_ver.map(str::to_string);
3515        wrap_function(&config, false, |p| p.print_version(&file_ver, ver_width))
3516    }
3517
3518    fn wrap_ext(file_ext: &str, ext_width: usize) -> String {
3519        let config = Config::default();
3520        wrap_function(&config, false, |p| p.print_ext(file_ext, ext_width))
3521    }
3522
3523    fn wrap_total(num_files: usize, num_dirs: usize) -> String {
3524        let config = Config::default();
3525        let mut total = Total::new(None);
3526        total.num_files = num_files;
3527        total.num_dirs = num_dirs;
3528        wrap_function(&config, false, |p| p.print_summary(&total))
3529    }
3530
3531    fn wrap_files(config: &Config, git_bash: bool, files: &Vec<File>) -> String {
3532        let total = create_total(config, files);
3533        wrap_function(config, git_bash, |p| p.print_files(files, &total, &Utc))
3534    }
3535
3536    fn wrap_function<F>(config: &Config, git_bash: bool, func: F) -> String where
3537        F: FnOnce(&mut Printer<BufferWrapper>) -> MyResult<()>,
3538    {
3539        let mut buffer = String::new();
3540        let writer = unsafe { BufferWrapper::new(buffer.as_mut_vec()) };
3541        let colors = Some(String::from("*.gz=01;31:*.zip=01;31:*.png=01;35"));
3542        let colors = ColorMap::new(colors);
3543        let chars = IndentChars {
3544            branching: '+',
3545            terminating: '\\',
3546            horizontal: '-',
3547            vertical: '|',
3548        };
3549        let mut printer = Printer::new(
3550            config,
3551            &Utc,
3552            writer,
3553            colors,
3554            chars,
3555            git_bash,
3556        );
3557        func(&mut printer).unwrap();
3558        buffer
3559    }
3560
3561    fn create_files(drive: &str, abs_prefix: &str, rel_prefix: &str) -> Vec<File> {
3562        let abs_prefix = drive.to_string() + abs_prefix;
3563        let link_exec = PathBuf::from(drive.to_string() + "/etc/numbers/count.sh").clean();
3564        let link_file = PathBuf::from(drive.to_string() + "/etc/numbers/googolplex.gz").clean();
3565        let link_dir = PathBuf::from(drive.to_string() + "/etc/numbers/ordinals").clean();
3566        vec![
3567            create_file(&abs_prefix, rel_prefix, "example", "", "")
3568                .with_type(FileKind::Dir)
3569                .with_mode(0o755)
3570                .with_owner_ref("alice", "public")
3571                .with_size(0)
3572                .with_date(2023, 12, 31),
3573            create_file(&abs_prefix, rel_prefix, "example", "find", ".sh")
3574                .with_type(FileKind::File(ExecKind::Other))
3575                .with_mode(0o755)
3576                .with_owner_ref("root", "root")
3577                .with_size(10)
3578                .with_date(2023, 11, 01)
3579                .with_git(Some(GitFlags::default()
3580                    .with_added(true)
3581                    .with_modified(true)
3582                    .with_renamed(true)
3583                    .with_untracked(true)
3584                    .with_ignored(true)))
3585                .with_sig_str("#!/u"),
3586            create_file(&abs_prefix, rel_prefix, "example/files", "", "")
3587                .with_type(FileKind::Dir)
3588                .with_mode(0o755)
3589                .with_owner_ref("alice", "public")
3590                .with_size(0)
3591                .with_date(2023, 12, 31),
3592            create_file(&abs_prefix, rel_prefix, "example/files/colours", "", "")
3593                .with_type(FileKind::Dir)
3594                .with_mode(0o755)
3595                .with_owner_ref("alice", "public")
3596                .with_size(0)
3597                .with_date(2023, 12, 31),
3598            create_file(&abs_prefix, rel_prefix, "example/files/colours", "alpha", ".sh")
3599                .with_type(FileKind::File(ExecKind::User))
3600                .with_mode(0o744)
3601                .with_owner_ref("alice", "public")
3602                .with_size(20)
3603                .with_date(2023, 10, 01)
3604                .with_git(Some(GitFlags::default().with_added(true)))
3605                .with_sig_str("#!/u"),
3606            create_file(&abs_prefix, rel_prefix, "example/files/colours", "blue", ".txt")
3607                .with_type(FileKind::File(ExecKind::None))
3608                .with_mode(0o644)
3609                .with_owner_ref("alice", "public")
3610                .with_size(30)
3611                .with_date(2023, 09, 01)
3612                .with_git(Some(GitFlags::default().with_modified(true)))
3613                .with_sig_str("BLUE"),
3614            create_file(&abs_prefix, rel_prefix, "example/files/colours", "green", ".txt")
3615                .with_type(FileKind::File(ExecKind::None))
3616                .with_mode(0o644)
3617                .with_owner_ref("alice", "public")
3618                .with_size(40)
3619                .with_date(2023, 08, 01)
3620                .with_git(Some(GitFlags::default().with_renamed(true)))
3621                .with_sig_str("GREE"),
3622            create_file(&abs_prefix, rel_prefix, "example/files/colours", "red", ".txt")
3623                .with_type(FileKind::File(ExecKind::None))
3624                .with_mode(0o644)
3625                .with_owner_ref("alice", "public")
3626                .with_size(50)
3627                .with_date(2023, 07, 01)
3628                .with_git(Some(GitFlags::default().with_untracked(true)))
3629                .with_sig_str("RED"),
3630            create_file(&abs_prefix, rel_prefix, "example/files/numbers", "", "")
3631                .with_type(FileKind::Dir)
3632                .with_mode(0o755)
3633                .with_owner_ref("bob", "public")
3634                .with_size(0)
3635                .with_date(2023, 12, 31),
3636            create_file(&abs_prefix, rel_prefix, "example/files/numbers", "count", ".sh")
3637                .with_type(FileKind::Link(true))
3638                .with_mode(0o744)
3639                .with_owner_ref("bob", "public")
3640                .with_size(60)
3641                .with_date(2023, 06, 01)
3642                .with_sig_str("#!/u")
3643                .with_link(link_exec, FileKind::File(ExecKind::User)),
3644            create_file(&abs_prefix, rel_prefix, "example/files/numbers", "googolplex", ".gz")
3645                .with_type(FileKind::Link(true))
3646                .with_mode(0o644)
3647                .with_owner_ref("bob", "public")
3648                .with_size(999)
3649                .with_date(2023, 05, 01)
3650                .with_link(link_file, FileKind::File(ExecKind::None)),
3651            create_file(&abs_prefix, rel_prefix, "example/files/numbers", "ordinals", "")
3652                .with_type(FileKind::Link(true))
3653                .with_mode(0o644)
3654                .with_owner_ref("bob", "public")
3655                .with_size(0)
3656                .with_date(2023, 04, 01)
3657                .with_link(link_dir, FileKind::Dir),
3658            create_file(&abs_prefix, rel_prefix, "example/files/numbers/one two", "", "")
3659                .with_type(FileKind::Dir)
3660                .with_mode(0o755)
3661                .with_size(0)
3662                .with_date(2023, 12, 31),
3663            create_file(&abs_prefix, rel_prefix, "example/files/numbers/one two", "\"three\" 'four'", ".txt")
3664                .with_type(FileKind::File(ExecKind::None))
3665                .with_mode(0o644)
3666                .with_size(70)
3667                .with_date(2023, 03, 01)
3668                .with_git(Some(GitFlags::default().with_ignored(true)))
3669                .with_sig(Some([0xff, 0xfe, 0x33, 0x34])),
3670        ]
3671    }
3672
3673    fn modify_files_by_name(files: Vec<File>) -> Vec<File> {
3674        let mut files = files.into_iter()
3675            .filter(|file| file.file_type != FileKind::Dir)
3676            .collect::<Vec<File>>();
3677        files.sort_by(&compare_files_by_name);
3678        files
3679    }
3680
3681    fn compare_files_by_name(left: &File, right: &File) -> Ordering {
3682        let left = left.file_name.trim_start_matches("\"");
3683        let right = right.file_name.trim_start_matches("\"");
3684        left.cmp(&right)
3685    }
3686
3687    fn modify_files_for_zip(files: Vec<File>) -> Vec<File> {
3688        files.into_iter().map(modify_file_for_zip).collect()
3689    }
3690
3691    fn modify_file_for_zip(file: File) -> File {
3692        let (abs_dir, mut inner_depth) = modify_dir_for_zip(&file.abs_dir);
3693        let (rel_dir, _) = modify_dir_for_zip(&file.rel_dir);
3694        if file.file_type != FileKind::Dir {
3695            inner_depth = inner_depth.map(|depth| depth + 1);
3696        }
3697        file.with_dirs(abs_dir, rel_dir).with_inner_depth(inner_depth)
3698    }
3699
3700    fn modify_dir_for_zip(old_dir: &Path) -> (PathBuf, Option<usize>) {
3701        let mut new_dir = PathBuf::new();
3702        let mut inner_depth = None;
3703        for component in old_dir.components() {
3704            if let Component::Normal(dir) = component {
3705                if dir == "files" {
3706                    new_dir.push("files.zip");
3707                    inner_depth = Some(0);
3708                    continue;
3709                }
3710            }
3711            new_dir.push(component);
3712            inner_depth = inner_depth.map(|depth| depth + 1);
3713        }
3714        (new_dir, inner_depth)
3715    }
3716
3717    #[cfg(windows)]
3718    fn create_files_with_version() -> Vec<File> {
3719        vec![
3720            create_file("", "", "", "binary", ".exe")
3721                .with_type(FileKind::File(ExecKind::User))
3722                .with_mode(0o744)
3723                .with_size(999)
3724                .with_date(2024, 01, 01)
3725                .with_version(String::from("12.3.4.0")),
3726            create_file("", "", "", "library", ".dll")
3727                .with_type(FileKind::File(ExecKind::None))
3728                .with_mode(0o744)
3729                .with_size(999)
3730                .with_date(2024, 01, 01)
3731                .with_version(String::from("5.67.89.0")),
3732            create_file("", "", "", "readme", ".txt")
3733                .with_type(FileKind::File(ExecKind::None))
3734                .with_mode(0o644)
3735                .with_size(999)
3736                .with_date(2024, 01, 01),
3737        ]
3738    }
3739
3740    fn create_file(
3741        abs_prefix: &str,
3742        rel_prefix: &str,
3743        file_dir: &str,
3744        file_name: &str,
3745        file_ext: &str,
3746    ) -> File {
3747        let abs_dir = PathBuf::from(abs_prefix).join(file_dir).clean();
3748        let rel_dir = PathBuf::from(rel_prefix).join(file_dir).clean();
3749        let file_depth = PathBuf::from(file_dir).join(file_name).components().count();
3750        let file_name = format!("{file_name}{file_ext}");
3751        let file_ext = String::from(file_ext);
3752        File::new(abs_dir, rel_dir, file_depth, None, file_name, file_ext, FileKind::Other)
3753    }
3754
3755    fn create_total(config: &Config, files: &Vec<File>) -> Total {
3756        let start_time = Utc.with_ymd_and_hms(2023, 1, 1, 0, 0, 0).unwrap();
3757        Total::from_files(Some(start_time), config, files)
3758    }
3759
3760    struct BufferWrapper<'a> {
3761        buffer: &'a mut Vec<u8>,
3762    }
3763
3764    impl<'a> BufferWrapper<'a> {
3765        fn new(buffer: &'a mut Vec<u8>) -> Self {
3766            Self { buffer }
3767        }
3768    }
3769
3770    impl<'a> Write for BufferWrapper<'a> {
3771        fn write(&mut self, buffer: &[u8]) -> io::Result<usize> {
3772            self.buffer.write(buffer)
3773        }
3774
3775        fn flush(&mut self) -> io::Result<()> {
3776            Ok(())
3777        }
3778    }
3779
3780    impl<'a> WriteColor for BufferWrapper<'a> {
3781        fn supports_color(&self) -> bool {
3782            false
3783        }
3784
3785        fn set_color(&mut self, color: &ColorSpec) -> io::Result<()> {
3786            let bold = if color.bold() { "Lt" } else { "Dk" };
3787            let fg = match color.fg() {
3788                Some(Color::Black) => "Black",
3789                Some(Color::Blue) => "Blue",
3790                Some(Color::Green) => "Green",
3791                Some(Color::Red) => "Red",
3792                Some(Color::Cyan) => "Cyan",
3793                Some(Color::Magenta) => "Magenta",
3794                Some(Color::Yellow) => "Yellow",
3795                Some(Color::White) => "White",
3796                Some(_) => "Other",
3797                None => "None",
3798            };
3799            write!(&mut self.buffer, "[{bold}{fg}]")?;
3800            Ok(())
3801        }
3802
3803        fn reset(&mut self) -> io::Result<()> {
3804            write!(&mut self.buffer, "[Reset]")?;
3805            Ok(())
3806        }
3807    }
3808}