ex_cli/
printer.rs

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