file_dig/
lib.rs

1pub mod file_criteria;
2mod file_utils;
3
4use file_criteria::FindCriteria;
5
6#[derive(Debug)]
7pub enum FindError {
8    InvalidCriteria(String),
9    NotFound(String),
10    NotADirectory(String),
11}
12impl std::fmt::Display for FindError {
13    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
14        match self {
15            FindError::InvalidCriteria(e) => write!(f, "Invalid criteria: {}", e),
16            FindError::NotFound(p) => write!(f, "Path not found: {}", p),
17            FindError::NotADirectory(p) => write!(f, "Path is not a directory: {}", p),
18        }
19    }
20}
21impl std::error::Error for FindError {}
22
23pub fn find(path: &str, criteria: &FindCriteria) -> Result<Vec<String>, FindError> {
24    file_criteria::validate(criteria).map_err(|err| err)?;
25
26    let research_path = std::path::Path::new(path);
27
28    if !research_path.exists() {
29        return Err(FindError::NotFound(path.to_string()));
30    }
31
32    if !research_path.is_dir() {
33        return Err(FindError::NotADirectory(path.to_string()));
34    }
35
36    let mut found_files = Vec::new();
37
38    if let Ok(entries) = std::fs::read_dir(research_path) {
39        for entry_result in entries {
40            if let Ok(entry) = entry_result {
41                let file_path = entry.path();
42                if file_path.is_dir() && criteria.recursive {
43                    if let Some(subdirectory_path) = file_path.to_str() {
44                        if let Ok(subdirectory_files) = find(subdirectory_path, criteria) {
45                            found_files.extend(subdirectory_files);
46                        }
47                    }
48                } else if file_path.is_file() && file_utils::accept(&entry, criteria) {
49                    if let Some(file_str) = file_path.to_str() {
50                        found_files.push(file_str.to_string());
51                    }
52                }
53            }
54        }
55    }
56
57    Ok(found_files)
58}
59
60#[cfg(test)]
61mod tests {
62    use super::*;
63    use std::ffi::OsString;
64
65    #[test]
66    fn none_existing_path() {
67        let criteria = FindCriteria::new();
68        let result = find("tests_files/empty2", &criteria);
69        assert!(result.is_err());
70        assert_eq!(
71            result.unwrap_err().to_string(),
72            "Path not found: tests_files/empty2"
73        );
74    }
75
76    #[test]
77    fn path_is_a_file() {
78        let criteria = FindCriteria::new();
79        let result = find("tests_files/file", &criteria);
80        assert!(result.is_err());
81        assert_eq!(
82            result.unwrap_err().to_string(),
83            "Path is not a directory: tests_files/file"
84        );
85    }
86
87    #[test]
88    fn validate_file_size_min_greater_than_max() {
89        let criteria = FindCriteria::new()
90            .file_size_minimum(200)
91            .file_size_maximum(100);
92        let result = file_criteria::validate(&criteria);
93        assert!(result.is_err());
94        assert_eq!(
95            result.unwrap_err().to_string(),
96            "Invalid criteria: Minimum file size cannot be greater than maximum file size"
97        );
98    }
99
100    #[test]
101    fn all_files() {
102        let criteria = FindCriteria::new();
103        let result = find("tests_files", &criteria);
104        assert!(result.is_ok());
105        assert_eq!(result.unwrap().len(), 5);
106    }
107
108    #[test]
109    fn not_recursive_files() {
110        let criteria = FindCriteria::new().recursive(false);
111        let result = find("tests_files", &criteria);
112        assert!(result.is_ok());
113        assert_eq!(result.unwrap().len(), 3);
114    }
115
116    #[test]
117    fn search_name() {
118        let criteria = FindCriteria::new().file_name(OsString::from("f"));
119        let result = find("tests_files", &criteria);
120        assert!(result.is_ok());
121        assert_eq!(result.unwrap().len(), 2);
122    }
123
124    #[test]
125    fn search_png() {
126        let criteria = FindCriteria::new().file_extension(OsString::from("png"));
127        let result = find("tests_files", &criteria);
128        assert!(result.is_ok());
129        assert_eq!(result.unwrap().len(), 2);
130    }
131
132    #[test]
133    fn search_size_min() {
134        let criteria = FindCriteria::new().file_size_minimum(89534);
135        let result = find("tests_files", &criteria);
136        assert!(result.is_ok());
137        assert_eq!(result.unwrap().len(), 2);
138    }
139
140    #[test]
141    fn search_size_max() {
142        let criteria = FindCriteria::new().file_size_maximum(89534);
143        let result = find("tests_files", &criteria);
144        assert!(result.is_ok());
145        assert_eq!(result.unwrap().len(), 4);
146    }
147
148    #[test]
149    fn search_multiple_criteria() {
150        let criteria = FindCriteria::new()
151            .file_name(OsString::from("image"))
152            .file_extension(OsString::from("png"))
153            .file_size_minimum(89)
154            .file_size_maximum(100000);
155        let result = find("tests_files", &criteria);
156        assert!(result.is_ok());
157        assert_eq!(result.unwrap().len(), 1);
158    }
159}