From 9516a1aeeafe6479abc241b235905705130110aa Mon Sep 17 00:00:00 2001 From: Lucien Greathouse Date: Fri, 14 Dec 2018 18:03:56 -0800 Subject: [PATCH] Rework Imfs and expand tests a bit --- server/src/imfs.rs | 148 ++++++++++++++++++++++++++----------------- server/tests/imfs.rs | 68 ++++++++++++++++++-- 2 files changed, 155 insertions(+), 61 deletions(-) diff --git a/server/src/imfs.rs b/server/src/imfs.rs index 5891ff4a..655a2b43 100644 --- a/server/src/imfs.rs +++ b/server/src/imfs.rs @@ -64,23 +64,14 @@ impl Imfs { self.roots.insert(path.to_path_buf()); - ImfsItem::read_from_disk(self, path)?; - Ok(()) + self.read_from_disk(path) } pub fn path_created(&mut self, path: &Path) -> io::Result<()> { debug_assert!(path.is_absolute()); debug_assert!(self.is_within_roots(path)); - if let Some(parent_path) = path.parent() { - if self.is_within_roots(parent_path) && self.get(parent_path).is_none() { - self.path_created(parent_path)?; - } - } else { - ImfsItem::read_from_disk(self, path)?; - } - - Ok(()) + self.read_from_disk(path) } pub fn path_updated(&mut self, path: &Path) -> io::Result<()> { @@ -92,7 +83,7 @@ impl Imfs { self.path_created(parent_path)?; } } else { - ImfsItem::read_from_disk(self, path)?; + self.read_from_disk(path)?; } Ok(()) @@ -103,11 +94,7 @@ impl Imfs { debug_assert!(self.is_within_roots(path)); if let Some(parent_path) = path.parent() { - if self.is_within_roots(parent_path) { - if let Some(ImfsItem::Directory(parent)) = self.items.get_mut(parent_path) { - parent.children.remove(path); - } - } + self.unlink_child(parent_path, path); } if let Some(ImfsItem::Directory(directory)) = self.items.remove(path) { @@ -130,37 +117,35 @@ impl Imfs { Ok(()) } - fn is_within_roots(&self, path: &Path) -> bool { - for root_path in &self.roots { - if path.starts_with(root_path) { - return true; + fn unlink_child(&mut self, parent: &Path, child: &Path) { + let parent_item = self.items.get_mut(parent); + + match parent_item { + Some(ImfsItem::Directory(directory)) => { + directory.children.remove(child); + }, + _ => { + panic!("Tried to unlink child of path that wasn't a directory!"); + }, + } + } + + fn link_child(&mut self, parent: &Path, child: &Path) { + if self.is_within_roots(parent) { + let parent_item = self.items.get_mut(parent); + + match parent_item { + Some(ImfsItem::Directory(directory)) => { + directory.children.insert(child.to_path_buf()); + }, + _ => { + panic!("Tried to link child of path that wasn't a directory!"); + }, } } - - false } -} -#[derive(Debug, PartialEq)] -pub struct ImfsFile { - pub path: PathBuf, - pub contents: Vec, -} - -#[derive(Debug, PartialEq)] -pub struct ImfsDirectory { - pub path: PathBuf, - pub children: HashSet, -} - -#[derive(Debug, PartialEq)] -pub enum ImfsItem { - File(ImfsFile), - Directory(ImfsDirectory), -} - -impl ImfsItem { - fn read_from_disk<'a, 'b>(vfs: &'a mut Imfs, path: &'b Path) -> io::Result<&'a ImfsItem> { + fn read_from_disk(&mut self, path: &Path) -> io::Result<()> { let metadata = fs::metadata(path)?; if metadata.is_file() { @@ -170,31 +155,80 @@ impl ImfsItem { contents, }); - vfs.items.insert(path.to_path_buf(), item); + self.items.insert(path.to_path_buf(), item); - Ok(&vfs.items[path]) + if let Some(parent_path) = path.parent() { + self.link_child(parent_path, path); + } + + Ok(()) } else if metadata.is_dir() { - let mut children = HashSet::new(); + let item = ImfsItem::Directory(ImfsDirectory { + path: path.to_path_buf(), + children: HashSet::new(), + }); + + self.items.insert(path.to_path_buf(), item); for entry in fs::read_dir(path)? { let entry = entry?; let child_path = entry.path(); - ImfsItem::read_from_disk(vfs, &child_path)?; - - children.insert(child_path); + self.read_from_disk(&child_path)?; } - let item = ImfsItem::Directory(ImfsDirectory { - path: path.to_path_buf(), - children, - }); + if let Some(parent_path) = path.parent() { + self.link_child(parent_path, path); + } - vfs.items.insert(path.to_path_buf(), item); - - Ok(&vfs.items[path]) + Ok(()) } else { panic!("Unexpected non-file, non-directory item"); } } + + fn is_within_roots(&self, path: &Path) -> bool { + let kind = self.classify_path(path); + + kind == PathKind::Root || kind == PathKind::InRoot + } + + fn classify_path(&self, path: &Path) -> PathKind { + for root_path in &self.roots { + if root_path == path { + return PathKind::Root; + } + + if path.starts_with(root_path) { + return PathKind::InRoot; + } + } + + PathKind::NotInRoot + } +} + +#[derive(Debug, Clone, Copy, PartialEq)] +enum PathKind { + Root, + InRoot, + NotInRoot, +} + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +pub struct ImfsFile { + pub path: PathBuf, + pub contents: Vec, +} + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +pub struct ImfsDirectory { + pub path: PathBuf, + pub children: HashSet, +} + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +pub enum ImfsItem { + File(ImfsFile), + Directory(ImfsDirectory), } \ No newline at end of file diff --git a/server/tests/imfs.rs b/server/tests/imfs.rs index a6fd40ff..4e32df8a 100644 --- a/server/tests/imfs.rs +++ b/server/tests/imfs.rs @@ -5,7 +5,7 @@ use std::{ path::PathBuf, }; -use tempfile::tempdir; +use tempfile::{TempDir, tempdir}; use librojo::{ imfs::{Imfs, ImfsItem, ImfsFile, ImfsDirectory}, @@ -16,18 +16,30 @@ struct ExpectedImfs { items: HashMap, } +struct TestResources { + foo_path: PathBuf, + bar_path: PathBuf, + baz_path: PathBuf, +} + fn check_expected(real: &Imfs, expected: &ExpectedImfs) { assert_eq!(real.get_roots(), &expected.roots); assert_eq!(real.get_items(), &expected.items); } -fn base_tree() -> io::Result<(Imfs, ExpectedImfs)> { +fn base_tree() -> io::Result<(TempDir, Imfs, ExpectedImfs, TestResources)> { let root = tempdir()?; let foo_path = root.path().join("foo"); let bar_path = root.path().join("bar.txt"); let baz_path = foo_path.join("baz.txt"); + let resources = TestResources { + foo_path: foo_path.clone(), + bar_path: bar_path.clone(), + baz_path: baz_path.clone(), + }; + fs::create_dir(&foo_path)?; fs::write(&bar_path, b"bar")?; fs::write(&baz_path, b"baz")?; @@ -80,12 +92,60 @@ fn base_tree() -> io::Result<(Imfs, ExpectedImfs)> { items: expected_items, }; - Ok((imfs, expected_imfs)) + Ok((root, imfs, expected_imfs, resources)) } #[test] fn initial_read() -> io::Result<()> { - let (imfs, expected_imfs) = base_tree()?; + let (root, imfs, expected_imfs, _) = base_tree()?; + + check_expected(&imfs, &expected_imfs); + + Ok(()) +} + +#[test] +fn adding_files() -> io::Result<()> { + let (root, mut imfs, mut expected_imfs, resources) = base_tree()?; + + check_expected(&imfs, &expected_imfs); + + let add_one_path = root.path().join("add_one.txt"); + let add_two_path = resources.foo_path.join("add_two.txt"); + + fs::write(&add_one_path, b"add_one")?; + fs::write(&add_two_path, b"add_two")?; + + imfs.path_created(&add_one_path)?; + imfs.path_created(&add_two_path)?; + + match expected_imfs.items.get_mut(root.path()) { + Some(ImfsItem::Directory(directory)) => { + directory.children.insert(add_one_path.clone()); + }, + _ => unreachable!(), + } + + match expected_imfs.items.get_mut(&resources.foo_path) { + Some(ImfsItem::Directory(directory)) => { + directory.children.insert(add_two_path.clone()); + }, + _ => unreachable!(), + } + + expected_imfs.items.insert(add_one_path.clone(), ImfsItem::File(ImfsFile { + path: add_one_path.clone(), + contents: b"add_one".to_vec(), + })); + + expected_imfs.items.insert(add_two_path.clone(), ImfsItem::File(ImfsFile { + path: add_two_path.clone(), + contents: b"add_two".to_vec(), + })); + + println!("{}", serde_json::to_string(imfs.get_items()).unwrap()); + println!("---------------------------------------------------------------"); + println!("{}", serde_json::to_string(&expected_imfs.items).unwrap()); check_expected(&imfs, &expected_imfs);