diff --git a/server/Cargo.lock b/server/Cargo.lock index 686447ec..e12aa45e 100644 --- a/server/Cargo.lock +++ b/server/Cargo.lock @@ -608,6 +608,7 @@ dependencies = [ "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -725,6 +726,18 @@ dependencies = [ "remove_dir_all 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "tempfile" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "remove_dir_all 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "term" version = "0.2.14" @@ -1021,6 +1034,7 @@ dependencies = [ "checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" "checksum syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "91b52877572087400e83d24b9178488541e3d535259e04ff17a63df1e5ceff59" "checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" +"checksum tempfile 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "439d9a7c00f98b1b5ee730039bf5b1f9203d508690e3c76b509e7ad59f8f7c99" "checksum term 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "f2077e54d38055cf1ca0fd7933a2e00cd3ec8f6fed352b2a377f06dcdaaf3281" "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" "checksum textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0b59b6b4b44d867f1370ef1bd91bfb262bf07bf0ae65c202ea2fbc16153b693" diff --git a/server/Cargo.toml b/server/Cargo.toml index d8342563..86d29ab9 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -24,3 +24,6 @@ notify = "4.0.0" rand = "0.3" regex = "0.2" lazy_static = "1.0" + +[dev-dependencies] +tempfile = "3" diff --git a/server/src/lib.rs b/server/src/lib.rs index 6c524342..1d9e0325 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -7,6 +7,9 @@ extern crate serde; extern crate serde_json; extern crate regex; +#[cfg(test)] +extern crate tempfile; + pub mod rbx_session; pub mod id; pub mod web; diff --git a/server/src/rbx_session.rs b/server/src/rbx_session.rs index aa3a44c3..0778b5d3 100644 --- a/server/src/rbx_session.rs +++ b/server/src/rbx_session.rs @@ -1,17 +1,22 @@ use std::path::{Path, PathBuf}; use std::collections::HashMap; -use std::io::Read; +use std::io::{Read, Write}; use std::fs::{self, File}; use id::{Id}; +// TODO: Add lifetime, switch to using Cow<'a, str> instead of String. It's +// possible that it would be too cumbersome! #[derive(Debug, Clone)] struct FileRoute { - partition: String, - route: Vec, + pub partition: String, + pub route: Vec, } impl FileRoute { + /// Creates a PathBuf out of the `FileRoute` based on the given partition + /// `Path`. + // TODO: Tests pub fn to_path_buf(&self, partition_path: &Path) -> PathBuf { let mut result = partition_path.to_path_buf(); @@ -22,6 +27,9 @@ impl FileRoute { result } + /// Creates a version of the FileRoute with the given extra pieces appended + /// to the end. + // TODO: Test pub fn extended_with(&self, pieces: &[&str]) -> FileRoute { let mut result = self.clone(); @@ -33,6 +41,9 @@ impl FileRoute { } } +/// Represents a file or directory that has been read from the filesystem. +// TODO: Keep track of file Path or FileRoute? +#[derive(Debug, Clone)] enum FileItem { File { contents: String, @@ -43,32 +54,44 @@ enum FileItem { } struct RbxInstance { - parent: Option, + pub parent: Option, } struct RbxSession { - partitions_path: HashMap, - partition_instances: HashMap, - partition_files: HashMap, + pub partition_paths: HashMap, + pub partition_instances: HashMap, + pub partition_files: HashMap, } impl RbxSession { + fn new() -> RbxSession { + RbxSession { + partition_paths: HashMap::new(), + partition_instances: HashMap::new(), + partition_files: HashMap::new(), + } + } + fn load(&mut self) { - for (partition_name, partition_path) in &self.partitions_path { - let file_item = self.read(&FileRoute { + for (partition_name, partition_path) in &self.partition_paths { + let route = FileRoute { partition: partition_name.clone(), route: vec![], - }).expect("aaagh"); + }; + + let file_item = self.read(&route).expect("Couldn't load partitions"); self.partition_files.insert(partition_name.clone(), file_item); } } fn read(&self, route: &FileRoute) -> Result { - let partition_path = self.partitions_path.get(&route.partition) + let partition_path = self.partition_paths.get(&route.partition) .ok_or(())?; let path = route.to_path_buf(partition_path); + println!("Read {:?}, path {}", route, path.display()); + let metadata = fs::metadata(path) .map_err(|_| ())?; @@ -82,7 +105,7 @@ impl RbxSession { } fn read_file(&self, route: &FileRoute) -> Result { - let partition_path = self.partitions_path.get(&route.partition) + let partition_path = self.partition_paths.get(&route.partition) .ok_or(())?; let path = route.to_path_buf(partition_path); @@ -100,7 +123,7 @@ impl RbxSession { } fn read_directory(&self, route: &FileRoute) -> Result { - let partition_path = self.partitions_path.get(&route.partition) + let partition_path = self.partition_paths.get(&route.partition) .ok_or(())?; let path = route.to_path_buf(partition_path); @@ -118,12 +141,9 @@ impl RbxSession { let child_route = route.extended_with(&[&name]); - match self.read(&child_route) { - Ok(child_item) => { - children.insert(name, child_item); - }, - Err(_) => {}, - } + let child_item = self.read(&child_route)?; + + children.insert(name, child_item); } Ok(FileItem::Directory { @@ -131,3 +151,51 @@ impl RbxSession { }) } } + +#[cfg(test)] +mod tests { + use super::*; + use tempfile; + + // I'm not exactly sure how I want to structure these tests + // Essentially, I need a bunch of random files to load, and to measure: + // * What FileItems were loaded? + // * Are changes logged to those FileItems correctly? + // * What RbxInstance objects are generated from them? + // * Are changes propagated from FileItem through to those RbxInstances? + + #[test] + fn file_items_correct() { + let root_dir = tempfile::tempdir().unwrap(); + + let foo_path = root_dir.path().join("foo.txt"); + let bar_path = root_dir.path().join("bar.tsv"); + + { + let mut foo = File::create(foo_path).unwrap(); + writeln!(foo, "Hello, foo!").unwrap(); + + let mut bar = File::create(bar_path).unwrap(); + writeln!(bar, "Hello, bar!").unwrap(); + } + + let mut session = RbxSession::new(); + + session.partition_paths.insert("agh".to_string(), root_dir.path().to_path_buf()); + + session.load(); + + assert_eq!(session.partition_files.len(), 1); + + let folder = session.partition_files.values().nth(0).unwrap(); + + let children = match folder { + &FileItem::Directory { ref children } => children, + _ => panic!("Not a directory!"), + }; + + assert_eq!(children.len(), 2); + assert!(children.get("foo.txt").is_some()); + assert!(children.get("bar.tsv").is_some()); + } +}