diff --git a/justfile b/justfile index 63a3a1a..d503ca2 100644 --- a/justfile +++ b/justfile @@ -1,3 +1,8 @@ +build: + cargo build + cargo test + cargo clippy + install-hooks: @echo "Installing git hooks" git config core.hooksPath .git-hooks diff --git a/tests/fs.rs b/tests/fs.rs new file mode 100644 index 0000000..a2d271a --- /dev/null +++ b/tests/fs.rs @@ -0,0 +1,312 @@ +use assert2::let_assert; + +use kxio::fs; + +type TestResult = Result<(), fs::Error>; + +mod path_of { + use super::*; + + #[test] + fn validate_fails_on_path_traversal() -> TestResult { + let fs = fs::temp().expect("temp fs"); + + let_assert!(Err(fs::Error::PathTraversal { base, path: _path }) = fs.path_of("..".into())); + assert_eq!(base, fs.base()); + + Ok(()) + } + + #[test] + fn matches_joins() -> TestResult { + let fs = fs::temp().expect("temp fs"); + + let joined = fs.base().join("foo").join("bar"); + let path_of = fs + .path_of("foo/bar".into()) + .expect("parse foo/bar into path"); + + assert_eq!(joined, path_of); + + Ok(()) + } +} + +mod file { + use super::*; + + #[test] + /// Write to a file, read it, verify it exists, is a file and has the expected contents + fn write_read_file_exists() -> TestResult { + let fs = fs::temp().expect("temp fs"); + let pathbuf = fs.base().join("foo"); + + let mut file = fs.file(&pathbuf); + file.write("content").expect("write"); + let c = file.reader().expect("reader").to_string(); + assert_eq!(c, "content"); + + let mut path = fs.path(&pathbuf); + let exists = path.exists().expect("exists"); + assert!(exists); + + let is_file = path.is_file().expect("is_file"); + assert!(is_file); + + Ok(()) + } +} + +mod dir_create { + use super::*; + #[test] + fn should_create_a_dir() -> TestResult { + let fs = fs::temp().expect("temp fs"); + let pathbuf = fs.base().join("subdir"); + + fs.dir(&pathbuf).create().expect("create"); + + let exists = fs.path(&pathbuf).exists().expect("exitss"); + assert!(exists); + + let is_dir = fs.path(&pathbuf).is_dir().expect("is dir"); + assert!(is_dir); + + Ok(()) + } + #[test] + fn should_fail_on_path_traversal() -> TestResult { + let fs = fs::temp().expect("temp fs"); + let path = fs.base().join("..").join("foo"); + let_assert!( + Err(fs::Error::PathTraversal { + base: _base, + path: _path + }) = fs.dir(&path).create() + ); + + Ok(()) + } +} + +mod dir_create_all { + use super::*; + + #[test] + fn should_create_a_dir() -> TestResult { + let fs = fs::temp().expect("temp fs"); + let pathbuf = fs.base().join("subdir").join("child"); + + fs.dir(&pathbuf).create_all().expect("create_all"); + + let mut path = fs.path(&pathbuf); + let exists = path.exists().expect("exists"); + assert!(exists, "path exists"); + + let is_dir = path.is_dir().expect("is_dir"); + assert!(is_dir, "path is a directory"); + + Ok(()) + } + #[test] + fn should_fail_on_path_traversal() -> TestResult { + let fs = fs::temp().expect("temp fs"); + let path = fs.base().join("..").join("foo"); + let_assert!( + Err(fs::Error::PathTraversal { + base: _base, + path: _path + }) = fs.dir(&path).create_all() + ); + + Ok(()) + } +} + +mod dir_dir_read { + use crate::fs::DirItem; + + use super::*; + + #[test] + fn should_return_dir_items() -> TestResult { + let fs = fs::temp().expect("temp fs"); + let file1 = fs.base().join("file-1"); + let dir = fs.base().join("dir"); + let file2 = dir.join("file-2"); + fs.file(&file1).write("file-1").expect("write: file-1"); + fs.dir(&dir).create().expect("create dir"); + fs.file(&file2).write("file-2").expect("write: file-2"); + + let items = fs + .dir(fs.base()) + .read() + .expect("dir.read") + .filter_map(|i| i.ok()) + .collect::>(); + + assert_eq!(items.len(), 2); + assert!(items.contains(&DirItem::File(file1))); + assert!(items.contains(&DirItem::Dir(dir))); + + Ok(()) + } + #[test] + fn should_fail_on_not_a_dir() -> TestResult { + let fs = fs::temp().expect("temp fs"); + let path = fs.base().join("file"); + fs.file(&path).write("contents").expect("write"); + + let_assert!(Err(fs::Error::NotADirectory { path: _path }) = fs.dir(&path).read()); + + Ok(()) + } + #[test] + fn should_fail_on_path_traversal() -> TestResult { + let fs = fs::temp().expect("temp fs"); + let path = fs.base().join("..").join("foo"); + let_assert!( + Err(fs::Error::PathTraversal { + base: _base, + path: _path + }) = fs.dir(&path).read() + ); + + Ok(()) + } +} + +mod path_exists { + use super::*; + #[test] + fn should_be_true_when_it_exists() -> TestResult { + let fs = fs::temp().expect("temp fs"); + let path = fs.base().join("foo"); + fs.file(&path).write("bar").expect("write"); + let exists = fs.path(&path).exists().expect("exists"); + assert!(exists); + + Ok(()) + } + #[test] + fn should_be_false_when_it_does_not_exist() -> TestResult { + let fs = fs::temp().expect("temp fs"); + let path = fs.base().join("foo"); + let exists = fs.path(&path).exists().expect("exists"); + assert!(!exists); + + Ok(()) + } + #[test] + fn should_fail_on_path_traversal() -> TestResult { + let fs = fs::temp().expect("temp fs"); + let path = fs.base().join("..").join("foo"); + let_assert!( + Err(fs::Error::PathTraversal { + base: _base, + path: _path + }) = fs.path(&path).exists() + ); + + Ok(()) + } +} + +mod path_is_dir { + use super::*; + #[test] + fn should_be_true_when_is_a_dir() -> TestResult { + let fs = fs::temp().expect("temp fs"); + let path = fs.base().join("foo"); + fs.dir(&path).create().expect("create"); + let is_dir = fs.path(&path).is_dir().expect("is_dir"); + assert!(is_dir); + + Ok(()) + } + #[test] + fn should_be_false_when_is_a_file() -> TestResult { + let fs = fs::temp().expect("temp fs"); + let path = fs.base().join("foo"); + fs.file(&path).write("bar").expect("write"); + let is_dir = fs.path(&path).is_dir().expect("is_dir"); + assert!(!is_dir); + + Ok(()) + } + #[test] + #[ignore] + fn should_be_false_when_is_a_link() -> TestResult { + let fs = fs::temp().expect("temp fs"); + let path = fs.base().join("foo"); + // TODO: (#38) create a link + // let_assert!(Ok(_) = fs.file_write(&path, "bar")); + let is_dir = fs.path(&path).is_dir().expect("is_dir"); + assert!(!is_dir); + + Ok(()) + } + #[test] + fn should_fail_on_path_traversal() -> TestResult { + let fs = fs::temp().expect("temp fs"); + let path = fs.base().join("..").join("foo"); + let_assert!( + Err(fs::Error::PathTraversal { + base: _base, + path: _path + }) = fs.dir(&path).is_dir() + ); + + Ok(()) + } +} + +mod path_is_file { + use super::*; + #[test] + fn should_be_true_when_is_a_file() -> TestResult { + let fs = fs::temp().expect("temp fs"); + let path = fs.base().join("foo"); + fs.file(&path).write("bar").expect("write"); + + let is_file = fs.path(&path).is_file().expect("is_file"); + assert!(is_file); + + Ok(()) + } + #[test] + fn should_be_false_when_is_a_dir() -> TestResult { + let fs = fs::temp().expect("temp fs"); + let path = fs.base().join("foo"); + fs.dir(&path).create().expect("create"); + let is_file = fs.path(&path).is_file().expect("is_file"); + assert!(!is_file); + + Ok(()) + } + #[test] + #[ignore] + fn should_be_false_when_is_a_link() -> TestResult { + let fs = fs::temp().expect("temp fs"); + let path = fs.base().join("foo"); + // TODO: (#38) create a link + // let_assert!(Ok(_) = fs.file_write(&path, "bar")); + let is_file = fs.path(&path).is_file().expect("is_file"); + assert!(!is_file); + + Ok(()) + } + #[test] + fn should_fail_on_path_traversal() -> TestResult { + let fs = fs::temp().expect("temp fs"); + let path = fs.base().join("..").join("foo"); + let_assert!( + Err(fs::Error::PathTraversal { + base: _base, + path: _path + }) = fs.file(&path).is_file() + ); + + Ok(()) + } +}