rust_serv/file_service/
file_service.rs1use crate::error::Result;
2use std::fs;
3use std::path::Path;
4
5#[derive(Debug, Clone)]
7pub struct FileMetadata {
8 pub path: String,
9 pub name: String,
10 pub size: u64,
11 pub is_dir: bool,
12}
13
14pub struct FileService;
16
17impl FileService {
18 pub fn read_file(path: &Path) -> Result<Vec<u8>> {
20 if !path.exists() {
21 return Err(crate::error::Error::NotFound(path.display().to_string()));
22 }
23 fs::read(path).map_err(Into::into)
24 }
25
26 pub fn is_directory(path: &Path) -> bool {
28 path.is_dir()
29 }
30
31 pub fn list_directory(path: &Path) -> Result<Vec<FileMetadata>> {
33 let entries = fs::read_dir(path)?;
34 let mut files = Vec::new();
35
36 for entry in entries {
37 let entry = entry?;
38 let metadata = entry.metadata()?;
39
40 let name = entry.file_name().to_string_lossy().to_string();
41
42 if name.starts_with('.') {
44 continue;
45 }
46
47 files.push(FileMetadata {
48 path: entry.path().display().to_string(),
49 name,
50 size: metadata.len(),
51 is_dir: metadata.is_dir(),
52 });
53 }
54
55 files.sort_by(|a, b| {
56 if a.is_dir && !b.is_dir {
58 return std::cmp::Ordering::Less;
59 }
60 if !a.is_dir && b.is_dir {
61 return std::cmp::Ordering::Greater;
62 }
63 a.name.cmp(&b.name)
65 });
66
67 Ok(files)
68 }
69}
70
71#[cfg(test)]
72mod tests {
73 use super::*;
74 use tempfile::TempDir;
75
76 #[test]
77 fn test_read_file() {
78 let temp_dir = TempDir::new().unwrap();
79 let file_path = temp_dir.path().join("test.txt");
80 fs::write(&file_path, "hello world").unwrap();
81
82 let content = FileService::read_file(&file_path).unwrap();
83 assert_eq!(content, b"hello world");
84 }
85
86 #[test]
87 fn test_read_nonexistent_file() {
88 let temp_dir = TempDir::new().unwrap();
89 let file_path = temp_dir.path().join("nonexistent.txt");
90
91 let result = FileService::read_file(&file_path);
92 assert!(result.is_err());
93 }
94
95 #[test]
96 fn test_list_directory() {
97 let temp_dir = TempDir::new().unwrap();
98 fs::write(temp_dir.path().join("file1.txt"), "content1").unwrap();
99 fs::write(temp_dir.path().join("file2.txt"), "content2").unwrap();
100 fs::create_dir(temp_dir.path().join("subdir")).unwrap();
101
102 let files = FileService::list_directory(temp_dir.path()).unwrap();
103 assert_eq!(files.len(), 3);
104 }
105
106 #[test]
107 fn test_list_directory_skips_hidden() {
108 let temp_dir = TempDir::new().unwrap();
109 fs::write(temp_dir.path().join("visible.txt"), "content").unwrap();
110 fs::write(temp_dir.path().join(".hidden.txt"), "hidden").unwrap();
111
112 let files = FileService::list_directory(temp_dir.path()).unwrap();
113 assert_eq!(files.len(), 1);
114 assert_eq!(files[0].name, "visible.txt");
115 }
116
117 #[test]
118 fn test_list_directory_nonexistent() {
119 let temp_dir = TempDir::new().unwrap();
120 let nonexist_path = temp_dir.path().join("nonexistent");
121
122 let result = FileService::list_directory(&nonexist_path);
123 assert!(result.is_err());
124 }
125
126 #[test]
127 fn test_list_directory_sorts_by_type() {
128 let temp_dir = TempDir::new().unwrap();
129 fs::create_dir(temp_dir.path().join("subdir")).unwrap();
130 fs::write(temp_dir.path().join("file.txt"), "content").unwrap();
131
132 let files = FileService::list_directory(temp_dir.path()).unwrap();
133 assert_eq!(files.len(), 2);
134 assert!(files[0].is_dir);
135 assert!(!files[1].is_dir);
136 }
137
138 #[test]
139 fn test_read_file_permission_error() {
140 let result = FileService::read_file(Path::new("/root/.bashrc"));
141 assert!(result.is_err());
143 }
144
145 #[test]
146 fn test_list_directory_empty() {
147 let temp_dir = TempDir::new().unwrap();
148 let files = FileService::list_directory(temp_dir.path()).unwrap();
151 assert_eq!(files.len(), 0);
152 }
153
154 #[test]
155 fn test_is_directory_true() {
156 let temp_dir = TempDir::new().unwrap();
157 let dir = temp_dir.path().join("testdir");
158 fs::create_dir(&dir).unwrap();
159
160 assert!(FileService::is_directory(&dir));
161 }
162
163 #[test]
164 fn test_is_directory_false() {
165 let temp_dir = TempDir::new().unwrap();
166 let file = temp_dir.path().join("testfile.txt");
167 fs::write(&file, "content").unwrap();
168
169 assert!(!FileService::is_directory(&file));
170 }
171
172 #[test]
173 fn test_is_directory_nonexistent() {
174 assert!(!FileService::is_directory(Path::new("/nonexistent/path")));
175 }
176}