filesystem/fake/
mod.rs

1use std::env;
2use std::ffi::{OsStr, OsString};
3use std::io::Result;
4use std::iter::Iterator;
5use std::path::{Path, PathBuf};
6use std::sync::{Arc, Mutex, MutexGuard};
7use std::vec::IntoIter;
8
9use FileSystem;
10#[cfg(unix)]
11use UnixFileSystem;
12#[cfg(feature = "temp")]
13use {TempDir, TempFileSystem};
14
15#[cfg(feature = "temp")]
16pub use self::tempdir::FakeTempDir;
17
18use self::registry::Registry;
19
20mod node;
21mod registry;
22#[cfg(feature = "temp")]
23mod tempdir;
24
25#[derive(Debug, Clone)]
26pub struct DirEntry {
27    parent: PathBuf,
28    file_name: OsString,
29}
30
31impl DirEntry {
32    fn new<P, S>(parent: P, file_name: S) -> Self
33    where
34        P: AsRef<Path>,
35        S: AsRef<OsStr>,
36    {
37        DirEntry {
38            parent: parent.as_ref().to_path_buf(),
39            file_name: file_name.as_ref().to_os_string(),
40        }
41    }
42}
43
44impl ::DirEntry for DirEntry {
45    fn file_name(&self) -> OsString {
46        self.file_name.clone()
47    }
48
49    fn path(&self) -> PathBuf {
50        self.parent.join(&self.file_name)
51    }
52}
53
54#[derive(Debug)]
55pub struct ReadDir(IntoIter<Result<DirEntry>>);
56
57impl ReadDir {
58    fn new(entries: Vec<Result<DirEntry>>) -> Self {
59        ReadDir(entries.into_iter())
60    }
61}
62
63impl Iterator for ReadDir {
64    type Item = Result<DirEntry>;
65
66    fn next(&mut self) -> Option<Self::Item> {
67        self.0.next()
68    }
69}
70
71impl ::ReadDir<DirEntry> for ReadDir {}
72
73/// An in-memory file system.
74#[derive(Clone, Debug, Default)]
75pub struct FakeFileSystem {
76    registry: Arc<Mutex<Registry>>,
77}
78
79impl FakeFileSystem {
80    pub fn new() -> Self {
81        let registry = Registry::new();
82
83        FakeFileSystem {
84            registry: Arc::new(Mutex::new(registry)),
85        }
86    }
87
88    fn apply<F, T>(&self, path: &Path, f: F) -> T
89    where
90        F: FnOnce(&MutexGuard<Registry>, &Path) -> T,
91    {
92        let registry = self.registry.lock().unwrap();
93        let storage;
94        let path = if path.is_relative() {
95            storage = registry
96                .current_dir()
97                .unwrap_or_else(|_| PathBuf::from("/"))
98                .join(path);
99            &storage
100        } else {
101            path
102        };
103
104        f(&registry, path)
105    }
106
107    fn apply_mut<F, T>(&self, path: &Path, mut f: F) -> T
108    where
109        F: FnMut(&mut MutexGuard<Registry>, &Path) -> T,
110    {
111        let mut registry = self.registry.lock().unwrap();
112        let storage;
113        let path = if path.is_relative() {
114            storage = registry
115                .current_dir()
116                .unwrap_or_else(|_| PathBuf::from("/"))
117                .join(path);
118            &storage
119        } else {
120            path
121        };
122
123        f(&mut registry, path)
124    }
125
126    fn apply_mut_from_to<F, T>(&self, from: &Path, to: &Path, mut f: F) -> T
127    where
128        F: FnMut(&mut MutexGuard<Registry>, &Path, &Path) -> T,
129    {
130        let mut registry = self.registry.lock().unwrap();
131        let from_storage;
132        let from = if from.is_relative() {
133            from_storage = registry
134                .current_dir()
135                .unwrap_or_else(|_| PathBuf::from("/"))
136                .join(from);
137            &from_storage
138        } else {
139            from
140        };
141        let to_storage;
142        let to = if to.is_relative() {
143            to_storage = registry
144                .current_dir()
145                .unwrap_or_else(|_| PathBuf::from("/"))
146                .join(to);
147            &to_storage
148        } else {
149            to
150        };
151
152        f(&mut registry, from, to)
153    }
154}
155
156impl FileSystem for FakeFileSystem {
157    type DirEntry = DirEntry;
158    type ReadDir = ReadDir;
159
160    fn current_dir(&self) -> Result<PathBuf> {
161        let registry = self.registry.lock().unwrap();
162        registry.current_dir()
163    }
164
165    fn set_current_dir<P: AsRef<Path>>(&self, path: P) -> Result<()> {
166        self.apply_mut(path.as_ref(), |r, p| r.set_current_dir(p.to_path_buf()))
167    }
168
169    fn is_dir<P: AsRef<Path>>(&self, path: P) -> bool {
170        self.apply(path.as_ref(), |r, p| r.is_dir(p))
171    }
172
173    fn is_file<P: AsRef<Path>>(&self, path: P) -> bool {
174        self.apply(path.as_ref(), |r, p| r.is_file(p))
175    }
176
177    fn create_dir<P: AsRef<Path>>(&self, path: P) -> Result<()> {
178        self.apply_mut(path.as_ref(), |r, p| r.create_dir(p))
179    }
180
181    fn create_dir_all<P: AsRef<Path>>(&self, path: P) -> Result<()> {
182        self.apply_mut(path.as_ref(), |r, p| r.create_dir_all(p))
183    }
184
185    fn remove_dir<P: AsRef<Path>>(&self, path: P) -> Result<()> {
186        self.apply_mut(path.as_ref(), |r, p| r.remove_dir(p))
187    }
188
189    fn remove_dir_all<P: AsRef<Path>>(&self, path: P) -> Result<()> {
190        self.apply_mut(path.as_ref(), |r, p| r.remove_dir_all(p))
191    }
192
193    fn read_dir<P: AsRef<Path>>(&self, path: P) -> Result<Self::ReadDir> {
194        let path = path.as_ref();
195
196        self.apply(path, |r, p| r.read_dir(p)).map(|entries| {
197            let entries = entries
198                .iter()
199                .map(|e| {
200                    let file_name = e.file_name().unwrap_or_else(|| e.as_os_str());
201
202                    Ok(DirEntry::new(path, &file_name))
203                })
204                .collect();
205
206            ReadDir::new(entries)
207        })
208    }
209
210    fn create_file<P, B>(&self, path: P, buf: B) -> Result<()>
211    where
212        P: AsRef<Path>,
213        B: AsRef<[u8]>,
214    {
215        self.apply_mut(path.as_ref(), |r, p| r.create_file(p, buf.as_ref()))
216    }
217
218    fn write_file<P, B>(&self, path: P, buf: B) -> Result<()>
219    where
220        P: AsRef<Path>,
221        B: AsRef<[u8]>,
222    {
223        self.apply_mut(path.as_ref(), |r, p| r.write_file(p, buf.as_ref()))
224    }
225
226    fn overwrite_file<P, B>(&self, path: P, buf: B) -> Result<()>
227    where
228        P: AsRef<Path>,
229        B: AsRef<[u8]>,
230    {
231        self.apply_mut(path.as_ref(), |r, p| r.overwrite_file(p, buf.as_ref()))
232    }
233
234    fn read_file<P: AsRef<Path>>(&self, path: P) -> Result<Vec<u8>> {
235        self.apply(path.as_ref(), |r, p| r.read_file(p))
236    }
237
238    fn read_file_to_string<P: AsRef<Path>>(&self, path: P) -> Result<String> {
239        self.apply(path.as_ref(), |r, p| r.read_file_to_string(p))
240    }
241
242    fn read_file_into<P, B>(&self, path: P, mut buf: B) -> Result<usize>
243    where
244        P: AsRef<Path>,
245        B: AsMut<Vec<u8>>,
246    {
247        self.apply(path.as_ref(), |r, p| r.read_file_into(p, buf.as_mut()))
248    }
249
250    fn remove_file<P: AsRef<Path>>(&self, path: P) -> Result<()> {
251        self.apply_mut(path.as_ref(), |r, p| r.remove_file(p))
252    }
253
254    fn copy_file<P, Q>(&self, from: P, to: Q) -> Result<()>
255    where
256        P: AsRef<Path>,
257        Q: AsRef<Path>,
258    {
259        self.apply_mut_from_to(from.as_ref(), to.as_ref(), |r, from, to| {
260            r.copy_file(from, to)
261        })
262    }
263
264    fn rename<P, Q>(&self, from: P, to: Q) -> Result<()>
265    where
266        P: AsRef<Path>,
267        Q: AsRef<Path>,
268    {
269        self.apply_mut_from_to(from.as_ref(), to.as_ref(), |r, from, to| r.rename(from, to))
270    }
271
272    fn readonly<P: AsRef<Path>>(&self, path: P) -> Result<bool> {
273        self.apply(path.as_ref(), |r, p| r.readonly(p))
274    }
275
276    fn set_readonly<P: AsRef<Path>>(&self, path: P, readonly: bool) -> Result<()> {
277        self.apply_mut(path.as_ref(), |r, p| r.set_readonly(p, readonly))
278    }
279
280    fn len<P: AsRef<Path>>(&self, path: P) -> u64 {
281        self.apply(path.as_ref(), |r, p| r.len(p))
282    }
283}
284
285#[cfg(unix)]
286impl UnixFileSystem for FakeFileSystem {
287    fn mode<P: AsRef<Path>>(&self, path: P) -> Result<u32> {
288        self.apply(path.as_ref(), |r, p| r.mode(p))
289    }
290
291    fn set_mode<P: AsRef<Path>>(&self, path: P, mode: u32) -> Result<()> {
292        self.apply_mut(path.as_ref(), |r, p| r.set_mode(p, mode))
293    }
294}
295
296#[cfg(feature = "temp")]
297impl TempFileSystem for FakeFileSystem {
298    type TempDir = FakeTempDir;
299
300    fn temp_dir<S: AsRef<str>>(&self, prefix: S) -> Result<Self::TempDir> {
301        let base = env::temp_dir();
302        let dir = FakeTempDir::new(Arc::downgrade(&self.registry), &base, prefix.as_ref());
303
304        self.create_dir_all(&dir.path()).and(Ok(dir))
305    }
306}