From 17f6f877b6328dece96eb5116705f28fdff71e11 Mon Sep 17 00:00:00 2001 From: Paul Campbell Date: Fri, 1 Nov 2024 08:54:55 +0000 Subject: [PATCH] test(fs): integration tests --- Cargo.toml | 5 - justfile | 5 + src/lib.rs | 3 - src/tests/mod.rs | 2 - tests/fs.rs | 312 +++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 317 insertions(+), 10 deletions(-) create mode 100644 tests/fs.rs diff --git a/Cargo.toml b/Cargo.toml index 5f9548f..4d544d9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,11 +8,6 @@ license = "MIT" repository = "https://git.kemitix.net/kemitix/kxio" exclude = [".cargo_home"] -[features] -default = ["fs", "network"] -fs = [] -network = [] - [lints.rust] unexpected_cfgs = { level = "warn", check-cfg = ['cfg(tarpaulin_include)'] } diff --git a/justfile b/justfile index 63a3a1a..e01dfe3 100644 --- a/justfile +++ b/justfile @@ -1,3 +1,8 @@ +build: + cargo hack --feature-powerset build + cargo hack --feature-powerset test + cargo hack --feature-powerset clippy + install-hooks: @echo "Installing git hooks" git config core.hooksPath .git-hooks diff --git a/src/lib.rs b/src/lib.rs index 3bf5b20..7f55398 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,5 @@ // -#[cfg(feature = "fs")] pub mod fs; - -#[cfg(feature = "network")] pub mod network; #[cfg(test)] diff --git a/src/tests/mod.rs b/src/tests/mod.rs index 2448679..e91d2f8 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -1,6 +1,4 @@ // -#[cfg(feature = "fs")] pub mod fs; -// #[cfg(feature = "network")] // pub mod network; 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(()) + } +}