image_optimizer/file_ops/
image_scanner.rs

1use std::ffi::OsStr;
2use std::path::PathBuf;
3use walkdir::WalkDir;
4
5const SUPPORTED_EXTENSIONS: &[&str] = &["jpg", "jpeg", "png", "webp"];
6
7pub fn scan_images(path: &std::path::Path, recursive: bool) -> Vec<PathBuf> {
8    let mut image_files = Vec::new();
9
10    if path.is_file() {
11        if let Some(extension) = path.extension().and_then(OsStr::to_str)
12            && SUPPORTED_EXTENSIONS.contains(&extension.to_lowercase().as_str())
13        {
14            image_files.push(path.to_path_buf());
15        }
16        return image_files;
17    }
18
19    let walker = if recursive {
20        WalkDir::new(path)
21    } else {
22        WalkDir::new(path).max_depth(1)
23    };
24
25    for entry in walker.into_iter().filter_map(Result::ok) {
26        if entry.file_type().is_file()
27            && let Some(extension) = entry.path().extension().and_then(OsStr::to_str)
28            && SUPPORTED_EXTENSIONS.contains(&extension.to_lowercase().as_str())
29        {
30            image_files.push(entry.path().to_path_buf());
31        }
32    }
33
34    image_files
35}
36
37#[cfg(test)]
38mod tests {
39    use super::*;
40    use std::fs;
41    use std::path::Path;
42
43    #[test]
44    fn test_supported_extensions() {
45        assert!(SUPPORTED_EXTENSIONS.contains(&"jpg"));
46        assert!(SUPPORTED_EXTENSIONS.contains(&"jpeg"));
47        assert!(SUPPORTED_EXTENSIONS.contains(&"png"));
48        assert!(SUPPORTED_EXTENSIONS.contains(&"webp"));
49        assert!(!SUPPORTED_EXTENSIONS.contains(&"gif"));
50        assert!(!SUPPORTED_EXTENSIONS.contains(&"txt"));
51    }
52
53    #[test]
54    fn test_scan_single_file() {
55        let temp_dir = std::env::temp_dir();
56        let test_file = temp_dir.join("test.jpg");
57        fs::write(&test_file, "fake jpg content").unwrap();
58
59        let result = scan_images(&test_file, false);
60        assert_eq!(result.len(), 1);
61        assert_eq!(result[0], test_file);
62
63        fs::remove_file(&test_file).unwrap();
64    }
65
66    #[test]
67    fn test_scan_unsupported_file() {
68        let temp_dir = std::env::temp_dir();
69        let test_file = temp_dir.join("test.txt");
70        fs::write(&test_file, "text content").unwrap();
71
72        let result = scan_images(&test_file, false);
73        assert_eq!(result.len(), 0);
74
75        fs::remove_file(&test_file).unwrap();
76    }
77
78    #[test]
79    fn test_scan_nonexistent_path() {
80        let nonexistent = Path::new("/nonexistent/path");
81        let result = scan_images(nonexistent, false);
82        assert_eq!(result.len(), 0);
83    }
84
85    #[test]
86    fn test_case_insensitive_extensions() {
87        let temp_dir = std::env::temp_dir();
88        let test_files = [
89            ("test_upper.JPG", "jpg"),
90            ("test_upper.JPEG", "jpeg"),
91            ("test_upper.PNG", "png"),
92            ("test_upper.WEBP", "webp"),
93        ];
94
95        for (filename, _) in &test_files {
96            let test_file = temp_dir.join(filename);
97            fs::write(&test_file, "fake content").unwrap();
98
99            let result = scan_images(&test_file, false);
100            assert_eq!(result.len(), 1, "Failed for file: {}", filename);
101            assert_eq!(result[0], test_file);
102
103            fs::remove_file(&test_file).unwrap();
104        }
105    }
106}