about summary refs log tree commit diff
path: root/src/filesystem.rs
diff options
context:
space:
mode:
authorMel <einebeere@gmail.com>2021-10-02 21:30:03 +0200
committerMel <einebeere@gmail.com>2021-10-02 21:30:03 +0200
commitcf01169e467f4ac36d2d8b9ce13e7bbc81d46aa5 (patch)
treed3b415c9480ff6d57b98d6f4355bd37636b7dd2e /src/filesystem.rs
parent55da5ae8cf731c768d6cc580693068e64234a4af (diff)
downloadka-cf01169e467f4ac36d2d8b9ce13e7bbc81d46aa5.tar.zst
ka-cf01169e467f4ac36d2d8b9ce13e7bbc81d46aa5.zip
Immutable Fs implementation and replaced exists calls.
Diffstat (limited to 'src/filesystem.rs')
-rw-r--r--src/filesystem.rs178
1 files changed, 81 insertions, 97 deletions
diff --git a/src/filesystem.rs b/src/filesystem.rs
index d8c96a1..74d7787 100644
--- a/src/filesystem.rs
+++ b/src/filesystem.rs
@@ -9,17 +9,17 @@ pub trait Fs {
     type File;
     type Entry: FsEntry;
 
-    fn create_file(&mut self, path: &Path) -> Result<Self::File>;
-    fn delete_file(&mut self, path: &Path) -> Result<()>;
-    fn open_readable_file(&mut self, path: &Path) -> Result<Self::File>;
-    fn open_writable_file(&mut self, path: &Path) -> Result<Self::File>;
+    fn create_file(&self, path: &Path) -> Result<Self::File>;
+    fn delete_file(&self, path: &Path) -> Result<()>;
+    fn open_readable_file(&self, path: &Path) -> Result<Self::File>;
+    fn open_writable_file(&self, path: &Path) -> Result<Self::File>;
 
-    fn read_directory(&mut self, path: &Path) -> Result<Vec<Self::Entry>>;
+    fn read_directory(&self, path: &Path) -> Result<Vec<Self::Entry>>;
 
-    fn write_to_file(&mut self, file: &mut Self::File, buffer: Vec<u8>) -> Result<()>;
-    fn read_from_file(&mut self, file: &mut Self::File) -> Result<Vec<u8>>;
+    fn write_to_file(&self, file: &mut Self::File, buffer: Vec<u8>) -> Result<()>;
+    fn read_from_file(&self, file: &mut Self::File) -> Result<Vec<u8>>;
 
-    fn path_exists(&mut self, path: &Path) -> bool;
+    fn path_exists(&self, path: &Path) -> bool;
 }
 
 pub trait FsEntry {
@@ -33,7 +33,7 @@ impl Fs for FsImpl {
     type File = File;
     type Entry = DirEntry;
 
-    fn create_file(&mut self, path: &Path) -> Result<Self::File> {
+    fn create_file(&self, path: &Path) -> Result<Self::File> {
         if let Some(parent_path) = path.parent() {
             if !parent_path.exists() {
                 fs::create_dir_all(parent_path)?;
@@ -48,17 +48,17 @@ impl Fs for FsImpl {
             .with_context(|| format!("Failed creating '{}'.", path.display()))
     }
 
-    fn delete_file(&mut self, path: &Path) -> Result<()> {
+    fn delete_file(&self, path: &Path) -> Result<()> {
         fs::remove_file(path)?;
         Ok(())
     }
 
-    fn open_readable_file(&mut self, path: &Path) -> Result<Self::File> {
+    fn open_readable_file(&self, path: &Path) -> Result<Self::File> {
         File::open(path)
             .with_context(|| format!("Failed opening '{}' for reading.", path.display()))
     }
 
-    fn open_writable_file(&mut self, path: &Path) -> Result<Self::File> {
+    fn open_writable_file(&self, path: &Path) -> Result<Self::File> {
         OpenOptions::new()
             .read(true)
             .write(true)
@@ -71,25 +71,25 @@ impl Fs for FsImpl {
             })
     }
 
-    fn read_directory(&mut self, path: &Path) -> Result<Vec<Self::Entry>> {
+    fn read_directory(&self, path: &Path) -> Result<Vec<Self::Entry>> {
         let result: io::Result<_> = fs::read_dir(path)?.collect();
         result.with_context(|| format!("Failed reading directory {}", path.display()))
     }
 
-    fn write_to_file(&mut self, file: &mut Self::File, buffer: Vec<u8>) -> Result<()> {
+    fn write_to_file(&self, file: &mut Self::File, buffer: Vec<u8>) -> Result<()> {
         file.rewind()?;
         file.set_len(0)?;
         file.write_all(&buffer)?;
         Ok(())
     }
 
-    fn read_from_file(&mut self, file: &mut Self::File) -> Result<Vec<u8>> {
+    fn read_from_file(&self, file: &mut Self::File) -> Result<Vec<u8>> {
         let mut buffer = Vec::new();
         file.read_to_end(&mut buffer)?;
         Ok(buffer)
     }
 
-    fn path_exists(&mut self, path: &Path) -> bool {
+    fn path_exists(&self, path: &Path) -> bool {
         path.exists()
     }
 }
@@ -109,36 +109,63 @@ impl FsEntry for DirEntry {
 #[allow(dead_code)]
 #[cfg(test)]
 pub mod mock {
-    use anyhow::{Error, Result};
-    use std::path::{Path, PathBuf};
+    use anyhow::Result;
+    use std::{
+        path::{Path, PathBuf},
+        sync::{Arc, Mutex},
+    };
 
     use super::{Fs, FsEntry};
 
     pub struct FsMock {
+        state: Arc<Mutex<FsMockState>>,
+    }
+
+    struct FsMockState {
         expected_calls: Vec<ExpectedCall>,
         received_calls: Vec<ReceivedCall>,
     }
 
     impl FsMock {
         pub fn new() -> Self {
-            FsMock {
+            let state = FsMockState {
                 expected_calls: Vec::new(),
                 received_calls: Vec::new(),
+            };
+
+            FsMock {
+                state: Arc::new(Mutex::new(state)),
             }
         }
+
+        fn add_call(&self, path: &Path, variant: ReceivedCallVariant) {
+            let call = ReceivedCall {
+                affected_path: path.to_path_buf(),
+                variant,
+            };
+
+            let mut state = self.state.lock().expect("File system mock lock poisoned.");
+            state.received_calls.push(call);
+        }
+
+        fn get_expected_call(&self) -> ExpectedCallVariant {
+            let state = self.state.lock().expect("File system lock poisoned.");
+
+            let expected_call = state
+                .expected_calls
+                .get(state.received_calls.len() - 1)
+                .expect("Unexpected call.");
+
+            expected_call.variant.clone()
+        }
     }
 
     impl Fs for FsMock {
         type File = FileMock;
         type Entry = EntryMock;
 
-        fn create_file(&mut self, path: &Path) -> Result<Self::File> {
-            let call = ReceivedCall {
-                affected_path: path.to_path_buf(),
-                variant: ReceivedCallVariant::FileCreated,
-            };
-
-            self.received_calls.push(call);
+        fn create_file(&self, path: &Path) -> Result<Self::File> {
+            self.add_call(path, ReceivedCallVariant::FileCreated);
 
             Ok(FileMock {
                 path: path.to_path_buf(),
@@ -146,24 +173,14 @@ pub mod mock {
             })
         }
 
-        fn delete_file(&mut self, path: &Path) -> Result<()> {
-            let call = ReceivedCall {
-                affected_path: path.to_path_buf(),
-                variant: ReceivedCallVariant::FileCreated,
-            };
-
-            self.received_calls.push(call);
+        fn delete_file(&self, path: &Path) -> Result<()> {
+            self.add_call(path, ReceivedCallVariant::FileDeleted);
 
             Ok(())
         }
 
-        fn open_readable_file(&mut self, path: &Path) -> Result<Self::File> {
-            let call = ReceivedCall {
-                affected_path: path.to_path_buf(),
-                variant: ReceivedCallVariant::ReadableFileOpened,
-            };
-
-            self.received_calls.push(call);
+        fn open_readable_file(&self, path: &Path) -> Result<Self::File> {
+            self.add_call(path, ReceivedCallVariant::ReadableFileOpened);
 
             Ok(FileMock {
                 path: path.to_path_buf(),
@@ -171,13 +188,8 @@ pub mod mock {
             })
         }
 
-        fn open_writable_file(&mut self, path: &Path) -> Result<Self::File> {
-            let call = ReceivedCall {
-                affected_path: path.to_path_buf(),
-                variant: ReceivedCallVariant::WritableFileOpened,
-            };
-
-            self.received_calls.push(call);
+        fn open_writable_file(&self, path: &Path) -> Result<Self::File> {
+            self.add_call(path, ReceivedCallVariant::WritableFileOpened);
 
             Ok(FileMock {
                 path: path.to_path_buf(),
@@ -185,73 +197,44 @@ pub mod mock {
             })
         }
 
-        fn read_directory(&mut self, path: &Path) -> Result<Vec<Self::Entry>> {
-            let call = ReceivedCall {
-                affected_path: path.to_path_buf(),
-                variant: ReceivedCallVariant::DirectoryRead,
-            };
-
-            self.received_calls.push(call);
+        fn read_directory(&self, path: &Path) -> Result<Vec<Self::Entry>> {
+            self.add_call(path, ReceivedCallVariant::DirectoryRead);
 
-            let expected_call_option = self.expected_calls.get(self.received_calls.len() - 1);
-
-            if let Some(expected_call) = expected_call_option {
-                if let ExpectedCallVariant::ReadDirectory { entries } = &expected_call.variant {
-                    return Ok(entries.to_vec());
-                }
+            if let ExpectedCallVariant::ReadDirectory { entries } = self.get_expected_call() {
+                Ok(entries.to_vec())
+            } else {
+                panic!("No content to read.");
             }
-
-            Err(Error::msg("No content to read."))
         }
 
-        fn write_to_file(&mut self, file: &mut Self::File, buffer: Vec<u8>) -> Result<()> {
-            let call = ReceivedCall {
-                affected_path: file.path.clone(),
-                variant: ReceivedCallVariant::FileWritten {
+        fn write_to_file(&self, file: &mut Self::File, buffer: Vec<u8>) -> Result<()> {
+            self.add_call(
+                &file.path,
+                ReceivedCallVariant::FileWritten {
                     written_content: buffer,
                 },
-            };
+            );
 
             // TODO: Check whether file was opened with write flag.
 
-            self.received_calls.push(call);
-
             Ok(())
         }
 
-        fn read_from_file(&mut self, file: &mut Self::File) -> Result<Vec<u8>> {
-            let call = ReceivedCall {
-                affected_path: file.path.clone(),
-                variant: ReceivedCallVariant::FileRead,
-            };
+        fn read_from_file(&self, file: &mut Self::File) -> Result<Vec<u8>> {
+            self.add_call(&file.path, ReceivedCallVariant::FileRead);
 
-            self.received_calls.push(call);
-
-            let expected_call_option = self.expected_calls.get(self.received_calls.len() - 1);
-
-            if let Some(expected_call) = expected_call_option {
-                if let ExpectedCallVariant::ReadFile { read_content } = &expected_call.variant {
-                    return Ok(read_content.clone());
-                }
+            if let ExpectedCallVariant::ReadFile { read_content } = self.get_expected_call() {
+                Ok(read_content.clone())
+            } else {
+                panic!("No content to read.");
             }
-
-            Err(Error::msg("No content to read."))
         }
 
-        fn path_exists(&mut self, path: &Path) -> bool {
-            let call = ReceivedCall {
-                affected_path: path.to_path_buf(),
-                variant: ReceivedCallVariant::DoesPathExist,
-            };
+        fn path_exists(&self, path: &Path) -> bool {
+            self.add_call(path, ReceivedCallVariant::DoesPathExist);
 
-            self.received_calls.push(call);
-
-            let expected_call_option = self.expected_calls.get(self.received_calls.len() - 1);
-
-            if let Some(expected_call) = expected_call_option {
-                if let ExpectedCallVariant::PathExists(answer) = &expected_call.variant {
-                    return *answer;
-                }
+            if let ExpectedCallVariant::PathExists(answer) = self.get_expected_call() {
+                return answer;
             }
 
             panic!("No mocked return value given for call.");
@@ -285,6 +268,7 @@ pub mod mock {
         pub variant: ExpectedCallVariant,
     }
 
+    #[derive(Clone)]
     pub enum ExpectedCallVariant {
         CreateFile,
         DeleteFile,