Compare commits
No commits in common. "bd4cb9ad61423e0143a14f91c9829e561ae12b06" and "2a5f47a9c9791694fa869a1b145ea44ca7022635" have entirely different histories.
bd4cb9ad61
...
2a5f47a9c9
5 changed files with 167 additions and 295 deletions
23
src/fs/like.rs
Normal file
23
src/fs/like.rs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
use crate::fs::DirItem;
|
||||||
|
|
||||||
|
use super::Result;
|
||||||
|
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
pub trait FileSystemLike {
|
||||||
|
fn base(&self) -> &Path;
|
||||||
|
|
||||||
|
fn dir_create(&self, path: &Path) -> Result<()>;
|
||||||
|
fn dir_create_all(&self, path: &Path) -> Result<()>;
|
||||||
|
|
||||||
|
/// Reads the items in a directory and returns them as an iterator.
|
||||||
|
fn dir_read(&self, path: &Path) -> Result<Box<dyn Iterator<Item = Result<DirItem>>>>;
|
||||||
|
|
||||||
|
fn file_read_to_string(&self, path: &Path) -> Result<String>;
|
||||||
|
fn file_write(&self, path: &Path, contents: &str) -> Result<()>;
|
||||||
|
|
||||||
|
fn path_exists(&self, path: &Path) -> Result<bool>;
|
||||||
|
fn path_is_dir(&self, path: &Path) -> Result<bool>;
|
||||||
|
fn path_is_file(&self, path: &Path) -> Result<bool>;
|
||||||
|
fn path_of(&self, path: PathBuf) -> Result<PathBuf>;
|
||||||
|
}
|
|
@ -2,14 +2,15 @@ use std::path::PathBuf;
|
||||||
|
|
||||||
use derive_more::From;
|
use derive_more::From;
|
||||||
|
|
||||||
|
use crate::fs::like::FileSystemLike;
|
||||||
|
|
||||||
|
mod like;
|
||||||
mod real;
|
mod real;
|
||||||
mod temp;
|
mod temp;
|
||||||
|
|
||||||
mod dir_item;
|
mod dir_item;
|
||||||
pub use dir_item::DirItem;
|
pub use dir_item::DirItem;
|
||||||
pub use dir_item::DirItemIterator;
|
pub use dir_item::DirItemIterator;
|
||||||
use real::FileSystem;
|
|
||||||
use temp::TempFileSystem;
|
|
||||||
|
|
||||||
#[derive(Debug, From, derive_more::Display)]
|
#[derive(Debug, From, derive_more::Display)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
|
@ -31,9 +32,25 @@ impl std::error::Error for Error {}
|
||||||
pub type Result<T> = core::result::Result<T, Error>;
|
pub type Result<T> = core::result::Result<T, Error>;
|
||||||
|
|
||||||
pub const fn new(base: PathBuf) -> FileSystem {
|
pub const fn new(base: PathBuf) -> FileSystem {
|
||||||
real::new(base)
|
FileSystem::Real(real::new(base))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn temp() -> Result<TempFileSystem> {
|
pub fn temp() -> Result<FileSystem> {
|
||||||
temp::new()
|
temp::new().map(FileSystem::Temp)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum FileSystem {
|
||||||
|
Real(real::RealFileSystem),
|
||||||
|
Temp(temp::TempFileSystem),
|
||||||
|
}
|
||||||
|
impl std::ops::Deref for FileSystem {
|
||||||
|
type Target = dyn FileSystemLike;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
match self {
|
||||||
|
Self::Real(fs) => fs,
|
||||||
|
Self::Temp(fs) => fs.deref(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
273
src/fs/real.rs
273
src/fs/real.rs
|
@ -1,44 +1,79 @@
|
||||||
use std::{
|
use std::path::{Path, PathBuf};
|
||||||
fmt::Display,
|
|
||||||
path::{Path, PathBuf},
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::fs::DirItem;
|
use crate::fs::{DirItem, DirItemIterator};
|
||||||
|
|
||||||
use super::{DirItemIterator, Result};
|
pub const fn new(base: PathBuf) -> RealFileSystem {
|
||||||
|
RealFileSystem { base }
|
||||||
pub const fn new(base: PathBuf) -> FileSystem {
|
|
||||||
FileSystem { base }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct FileSystem {
|
pub struct RealFileSystem {
|
||||||
base: PathBuf,
|
base: PathBuf,
|
||||||
}
|
}
|
||||||
impl FileSystem {
|
|
||||||
pub fn base(&self) -> &Path {
|
impl super::FileSystemLike for RealFileSystem {
|
||||||
|
fn base(&self) -> &Path {
|
||||||
&self.base
|
&self.base
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn path_of(&self, path: PathBuf) -> Result<PathBuf> {
|
fn dir_create(&self, path: &Path) -> super::Result<()> {
|
||||||
|
self.validate(path)?;
|
||||||
|
std::fs::create_dir(path).map_err(Into::into)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dir_create_all(&self, path: &Path) -> super::Result<()> {
|
||||||
|
self.validate(path)?;
|
||||||
|
std::fs::create_dir_all(path).map_err(Into::into)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dir_read(
|
||||||
|
&self,
|
||||||
|
path: &Path,
|
||||||
|
) -> super::Result<Box<dyn Iterator<Item = super::Result<DirItem>>>> {
|
||||||
|
self.validate(path)?;
|
||||||
|
if !self.path_is_dir(path)? {
|
||||||
|
return Err(super::Error::NotADirectory {
|
||||||
|
path: path.to_path_buf(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let read_dir = std::fs::read_dir(path)?;
|
||||||
|
Ok(Box::new(DirItemIterator::new(read_dir)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn file_read_to_string(&self, path: &Path) -> super::Result<String> {
|
||||||
|
self.validate(path)?;
|
||||||
|
std::fs::read_to_string(path).map_err(Into::into)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn file_write(&self, path: &Path, contents: &str) -> super::Result<()> {
|
||||||
|
self.validate(path)?;
|
||||||
|
std::fs::write(path, contents).map_err(Into::into)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn path_exists(&self, path: &Path) -> super::Result<bool> {
|
||||||
|
self.validate(path)?;
|
||||||
|
Ok(path.exists())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn path_is_dir(&self, path: &Path) -> super::Result<bool> {
|
||||||
|
self.validate(path)?;
|
||||||
|
Ok(path.is_dir())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn path_is_file(&self, path: &Path) -> super::Result<bool> {
|
||||||
|
self.validate(path)?;
|
||||||
|
Ok(path.is_file())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn path_of(&self, path: PathBuf) -> super::Result<PathBuf> {
|
||||||
let path_of = self.base.as_path().join(path);
|
let path_of = self.base.as_path().join(path);
|
||||||
self.validate(&path_of)?;
|
self.validate(&path_of)?;
|
||||||
Ok(path_of)
|
Ok(path_of)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn dir<'base, 'path>(&'base self, path: &'path Path) -> DirReal<'base, 'path> {
|
impl RealFileSystem {
|
||||||
DirReal::new(self.base(), path)
|
fn validate(&self, path: &Path) -> super::Result<()> {
|
||||||
}
|
|
||||||
|
|
||||||
pub fn file<'base, 'path>(&'base self, path: &'path Path) -> FileReal<'base, 'path> {
|
|
||||||
FileReal::new(self.base(), path)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn path<'base, 'path>(&'base self, path: &'path Path) -> PathReal<'base, 'path> {
|
|
||||||
PathReal::new(self.base(), path)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn validate(&self, path: &Path) -> Result<()> {
|
|
||||||
let path = self.clean_path(path)?;
|
let path = self.clean_path(path)?;
|
||||||
if !path.starts_with(&self.base) {
|
if !path.starts_with(&self.base) {
|
||||||
return Err(super::Error::PathTraversal {
|
return Err(super::Error::PathTraversal {
|
||||||
|
@ -49,7 +84,7 @@ impl FileSystem {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clean_path(&self, path: &Path) -> Result<PathBuf> {
|
fn clean_path(&self, path: &Path) -> super::Result<PathBuf> {
|
||||||
// let path = path.as_ref();
|
// let path = path.as_ref();
|
||||||
use path_clean::PathClean;
|
use path_clean::PathClean;
|
||||||
let abs_path = if path.is_absolute() {
|
let abs_path = if path.is_absolute() {
|
||||||
|
@ -61,187 +96,3 @@ impl FileSystem {
|
||||||
Ok(abs_path)
|
Ok(abs_path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DirReal<'base, 'path> {
|
|
||||||
path: PathReal<'base, 'path>,
|
|
||||||
}
|
|
||||||
impl<'base, 'path> DirReal<'base, 'path> {
|
|
||||||
fn new(base: &'base Path, path: &'path Path) -> Self {
|
|
||||||
let mut path = PathReal::new(base, path);
|
|
||||||
if path.error.is_none() {
|
|
||||||
if let Ok(exists) = path.exists() {
|
|
||||||
if exists {
|
|
||||||
if let Ok(is_dir) = path.is_dir() {
|
|
||||||
if !is_dir {
|
|
||||||
path.put(super::Error::NotADirectory {
|
|
||||||
path: path.full_path(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Self { path }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn create(&mut self) -> Result<()> {
|
|
||||||
self.path.check_error()?;
|
|
||||||
std::fs::create_dir(self.path.full_path()).map_err(Into::into)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn create_all(&mut self) -> Result<()> {
|
|
||||||
self.path.check_error()?;
|
|
||||||
std::fs::create_dir_all(self.path.full_path()).map_err(Into::into)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read(&mut self) -> Result<Box<dyn Iterator<Item = Result<DirItem>>>> {
|
|
||||||
self.path.check_error()?;
|
|
||||||
let read_dir = std::fs::read_dir(self.path.full_path())?;
|
|
||||||
Ok(Box::new(DirItemIterator::new(read_dir)))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn exists(&mut self) -> Result<bool> {
|
|
||||||
self.path.check_error()?;
|
|
||||||
self.path.exists()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_dir(&mut self) -> Result<bool> {
|
|
||||||
self.path.check_error()?;
|
|
||||||
Ok(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_file(&mut self) -> Result<bool> {
|
|
||||||
self.path.check_error()?;
|
|
||||||
Ok(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub struct FileReal<'base, 'path> {
|
|
||||||
path: PathReal<'base, 'path>,
|
|
||||||
}
|
|
||||||
impl<'base, 'path> FileReal<'base, 'path> {
|
|
||||||
fn new(base: &'base Path, path: &'path Path) -> Self {
|
|
||||||
Self {
|
|
||||||
path: PathReal::new(base, path),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn reader(&mut self) -> Result<ReaderReal> {
|
|
||||||
self.path.check_error()?;
|
|
||||||
ReaderReal::new(&self.path.full_path())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn write(&mut self, contents: &str) -> Result<()> {
|
|
||||||
self.path.check_error()?;
|
|
||||||
std::fs::write(self.path.full_path(), contents).map_err(Into::into)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn exists(&mut self) -> Result<bool> {
|
|
||||||
self.path.check_error()?;
|
|
||||||
self.path.exists()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_dir(&mut self) -> Result<bool> {
|
|
||||||
self.path.check_error()?;
|
|
||||||
Ok(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_file(&mut self) -> Result<bool> {
|
|
||||||
self.path.check_error()?;
|
|
||||||
Ok(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct PathReal<'base, 'path> {
|
|
||||||
base: &'base Path,
|
|
||||||
path: &'path Path,
|
|
||||||
error: Option<super::Error>,
|
|
||||||
}
|
|
||||||
impl<'base, 'path> PathReal<'base, 'path> {
|
|
||||||
fn full_path(&self) -> PathBuf {
|
|
||||||
self.base.join(self.path)
|
|
||||||
}
|
|
||||||
fn put(&mut self, error: super::Error) {
|
|
||||||
if self.error.is_none() {
|
|
||||||
self.error.replace(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn validate(base: &Path, path: &Path) -> Option<super::Error> {
|
|
||||||
match PathReal::clean_path(path) {
|
|
||||||
Err(error) => Some(error),
|
|
||||||
Ok(path) => {
|
|
||||||
if !path.starts_with(base) {
|
|
||||||
return Some(super::Error::PathTraversal {
|
|
||||||
base: base.to_path_buf(),
|
|
||||||
path,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clean_path(path: &Path) -> Result<PathBuf> {
|
|
||||||
// let path = path.as_ref();
|
|
||||||
use path_clean::PathClean;
|
|
||||||
let abs_path = if path.is_absolute() {
|
|
||||||
path.to_path_buf()
|
|
||||||
} else {
|
|
||||||
std::env::current_dir().expect("current_dir").join(path)
|
|
||||||
}
|
|
||||||
.clean();
|
|
||||||
Ok(abs_path)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new(base: &'base Path, path: &'path Path) -> Self {
|
|
||||||
Self {
|
|
||||||
base,
|
|
||||||
path,
|
|
||||||
error: PathReal::validate(base, path),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn exists(&mut self) -> Result<bool> {
|
|
||||||
self.check_error()?;
|
|
||||||
Ok(self.full_path().exists())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn check_error(&mut self) -> Result<()> {
|
|
||||||
if let Some(error) = self.error.take() {
|
|
||||||
return Err(error);
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_dir(&mut self) -> Result<bool> {
|
|
||||||
self.check_error()?;
|
|
||||||
Ok(self.full_path().is_dir())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_file(&mut self) -> Result<bool> {
|
|
||||||
self.check_error()?;
|
|
||||||
Ok(self.full_path().is_file())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl From<PathReal<'_, '_>> for PathBuf {
|
|
||||||
fn from(path: PathReal) -> Self {
|
|
||||||
path.base.join(path.path)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub struct ReaderReal {
|
|
||||||
contents: String,
|
|
||||||
}
|
|
||||||
impl ReaderReal {
|
|
||||||
fn new(path: &Path) -> Result<Self> {
|
|
||||||
let contents = std::fs::read_to_string(path)?;
|
|
||||||
Ok(Self { contents })
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn as_str(&self) -> &str {
|
|
||||||
&self.contents
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Display for ReaderReal {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(f, "{}", self.contents)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -2,8 +2,6 @@ use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use tempfile::TempDir;
|
use tempfile::TempDir;
|
||||||
|
|
||||||
use super::real::FileSystem;
|
|
||||||
|
|
||||||
pub(super) fn new() -> super::Result<TempFileSystem> {
|
pub(super) fn new() -> super::Result<TempFileSystem> {
|
||||||
let temp_dir = tempfile::tempdir()?;
|
let temp_dir = tempfile::tempdir()?;
|
||||||
let base = temp_dir.path().to_path_buf();
|
let base = temp_dir.path().to_path_buf();
|
||||||
|
@ -18,12 +16,12 @@ pub(super) fn new() -> super::Result<TempFileSystem> {
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct TempFileSystem {
|
pub struct TempFileSystem {
|
||||||
real: FileSystem,
|
real: super::real::RealFileSystem,
|
||||||
_temp_dir: Arc<Mutex<TempDir>>,
|
_temp_dir: Arc<Mutex<TempDir>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::ops::Deref for TempFileSystem {
|
impl std::ops::Deref for TempFileSystem {
|
||||||
type Target = FileSystem;
|
type Target = dyn super::FileSystemLike;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
&self.real
|
&self.real
|
||||||
|
|
133
src/tests/fs.rs
133
src/tests/fs.rs
|
@ -6,51 +6,36 @@ type TestResult = Result<(), fs::Error>;
|
||||||
|
|
||||||
mod path_of {
|
mod path_of {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn validate_fails_on_path_traversal() -> TestResult {
|
fn validate_fails_on_path_traversal() -> TestResult {
|
||||||
let fs = fs::temp().expect("temp fs");
|
let fs = fs::temp()?;
|
||||||
|
|
||||||
let_assert!(Err(fs::Error::PathTraversal { base, path: _path }) = fs.path_of("..".into()));
|
let_assert!(Err(fs::Error::PathTraversal { base, path: _path }) = fs.path_of("..".into()));
|
||||||
assert_eq!(base, fs.base());
|
assert_eq!(base, fs.base());
|
||||||
|
|
||||||
Ok(())
|
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 {
|
mod file {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
/// Write to a file, read it, verify it exists, is a file and has the expected contents
|
/// Write to a file, read it, verify it exists, is a file and has the expected contents
|
||||||
fn write_read_file_exists() -> TestResult {
|
fn write_read_file_exists() -> TestResult {
|
||||||
let fs = fs::temp().expect("temp fs");
|
let fs = fs::temp()?;
|
||||||
let pathbuf = fs.base().join("foo");
|
let pathbuf = fs.base().join("foo");
|
||||||
|
|
||||||
let mut file = fs.file(&pathbuf);
|
let_assert!(Ok(_) = fs.file_write(&pathbuf, "content"));
|
||||||
file.write("content").expect("write");
|
let_assert!(
|
||||||
let c = file.reader().expect("reader").to_string();
|
Ok(c) = fs.file_read_to_string(&pathbuf),
|
||||||
|
"file_read_to_string"
|
||||||
|
);
|
||||||
assert_eq!(c, "content");
|
assert_eq!(c, "content");
|
||||||
|
|
||||||
let mut path = fs.path(&pathbuf);
|
let_assert!(Ok(exists) = fs.path_exists(&pathbuf));
|
||||||
let exists = path.exists().expect("exists");
|
|
||||||
assert!(exists);
|
assert!(exists);
|
||||||
|
|
||||||
let is_file = path.is_file().expect("is_file");
|
let_assert!(Ok(is_file) = fs.path_is_file(&pathbuf));
|
||||||
assert!(is_file);
|
assert!(is_file);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -61,28 +46,28 @@ mod dir_create {
|
||||||
use super::*;
|
use super::*;
|
||||||
#[test]
|
#[test]
|
||||||
fn should_create_a_dir() -> TestResult {
|
fn should_create_a_dir() -> TestResult {
|
||||||
let fs = fs::temp().expect("temp fs");
|
let fs = fs::temp()?;
|
||||||
let pathbuf = fs.base().join("subdir");
|
let pathbuf = fs.base().join("subdir");
|
||||||
|
|
||||||
fs.dir(&pathbuf).create().expect("create");
|
let_assert!(Ok(_) = fs.dir_create(&pathbuf));
|
||||||
|
|
||||||
let exists = fs.path(&pathbuf).exists().expect("exitss");
|
let_assert!(Ok(exists) = fs.path_exists(&pathbuf));
|
||||||
assert!(exists);
|
assert!(exists);
|
||||||
|
|
||||||
let is_dir = fs.path(&pathbuf).is_dir().expect("is dir");
|
let_assert!(Ok(is_dir) = fs.path_is_dir(&pathbuf));
|
||||||
assert!(is_dir);
|
assert!(is_dir);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn should_fail_on_path_traversal() -> TestResult {
|
fn should_fail_on_path_traversal() -> TestResult {
|
||||||
let fs = fs::temp().expect("temp fs");
|
let fs = fs::temp()?;
|
||||||
let path = fs.base().join("..").join("foo");
|
let path = fs.base().join("..").join("foo");
|
||||||
let_assert!(
|
let_assert!(
|
||||||
Err(fs::Error::PathTraversal {
|
Err(fs::Error::PathTraversal {
|
||||||
base: _base,
|
base: _base,
|
||||||
path: _path
|
path: _path
|
||||||
}) = fs.dir(&path).create()
|
}) = fs.dir_create(&path)
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -94,29 +79,28 @@ mod dir_create_all {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_create_a_dir() -> TestResult {
|
fn should_create_a_dir() -> TestResult {
|
||||||
let fs = fs::temp().expect("temp fs");
|
let fs = fs::temp()?;
|
||||||
let pathbuf = fs.base().join("subdir").join("child");
|
let pathbuf = fs.base().join("subdir").join("child");
|
||||||
|
|
||||||
fs.dir(&pathbuf).create_all().expect("create_all");
|
let_assert!(Ok(_) = fs.dir_create_all(&pathbuf));
|
||||||
|
|
||||||
let mut path = fs.path(&pathbuf);
|
let_assert!(Ok(exists) = fs.path_exists(&pathbuf));
|
||||||
let exists = path.exists().expect("exists");
|
|
||||||
assert!(exists, "path exists");
|
assert!(exists, "path exists");
|
||||||
|
|
||||||
let is_dir = path.is_dir().expect("is_dir");
|
let_assert!(Ok(is_dir) = fs.path_is_dir(&pathbuf));
|
||||||
assert!(is_dir, "path is a directory");
|
assert!(is_dir, "path is a directory");
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn should_fail_on_path_traversal() -> TestResult {
|
fn should_fail_on_path_traversal() -> TestResult {
|
||||||
let fs = fs::temp().expect("temp fs");
|
let fs = fs::temp()?;
|
||||||
let path = fs.base().join("..").join("foo");
|
let path = fs.base().join("..").join("foo");
|
||||||
let_assert!(
|
let_assert!(
|
||||||
Err(fs::Error::PathTraversal {
|
Err(fs::Error::PathTraversal {
|
||||||
base: _base,
|
base: _base,
|
||||||
path: _path
|
path: _path
|
||||||
}) = fs.dir(&path).create_all()
|
}) = fs.dir_create_all(&path)
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -130,17 +114,16 @@ mod dir_dir_read {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_return_dir_items() -> TestResult {
|
fn should_return_dir_items() -> TestResult {
|
||||||
let fs = fs::temp().expect("temp fs");
|
let fs = fs::temp()?;
|
||||||
let file1 = fs.base().join("file-1");
|
let file1 = fs.base().join("file-1");
|
||||||
let dir = fs.base().join("dir");
|
let dir = fs.base().join("dir");
|
||||||
let file2 = dir.join("file-2");
|
let file2 = dir.join("file-2");
|
||||||
fs.file(&file1).write("file-1").expect("write: file-1");
|
fs.file_write(&file1, "file-1")?;
|
||||||
fs.dir(&dir).create().expect("create dir");
|
fs.dir_create(&dir)?;
|
||||||
fs.file(&file2).write("file-2").expect("write: file-2");
|
fs.file_write(&file2, "file-2")?;
|
||||||
|
|
||||||
let items = fs
|
let items = fs
|
||||||
.dir(fs.base())
|
.dir_read(fs.base())?
|
||||||
.read().expect("dir.read")
|
|
||||||
.filter_map(|i| i.ok())
|
.filter_map(|i| i.ok())
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
@ -152,23 +135,23 @@ mod dir_dir_read {
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn should_fail_on_not_a_dir() -> TestResult {
|
fn should_fail_on_not_a_dir() -> TestResult {
|
||||||
let fs = fs::temp().expect("temp fs");
|
let fs = fs::temp()?;
|
||||||
let path = fs.base().join("file");
|
let path = fs.base().join("file");
|
||||||
fs.file(&path).write("contents").expect("write");
|
fs.file_write(&path, "contents")?;
|
||||||
|
|
||||||
let_assert!(Err(fs::Error::NotADirectory { path: _path }) = fs.dir(&path).read());
|
let_assert!(Err(fs::Error::NotADirectory { path: _path }) = fs.dir_read(&path));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn should_fail_on_path_traversal() -> TestResult {
|
fn should_fail_on_path_traversal() -> TestResult {
|
||||||
let fs = fs::temp().expect("temp fs");
|
let fs = fs::temp()?;
|
||||||
let path = fs.base().join("..").join("foo");
|
let path = fs.base().join("..").join("foo");
|
||||||
let_assert!(
|
let_assert!(
|
||||||
Err(fs::Error::PathTraversal {
|
Err(fs::Error::PathTraversal {
|
||||||
base: _base,
|
base: _base,
|
||||||
path: _path
|
path: _path
|
||||||
}) = fs.dir(&path).read()
|
}) = fs.dir_read(&path)
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -179,32 +162,32 @@ mod path_exists {
|
||||||
use super::*;
|
use super::*;
|
||||||
#[test]
|
#[test]
|
||||||
fn should_be_true_when_it_exists() -> TestResult {
|
fn should_be_true_when_it_exists() -> TestResult {
|
||||||
let fs = fs::temp().expect("temp fs");
|
let fs = fs::temp()?;
|
||||||
let path = fs.base().join("foo");
|
let path = fs.base().join("foo");
|
||||||
fs.file(&path).write("bar").expect("write");
|
let_assert!(Ok(_) = fs.file_write(&path, "bar"));
|
||||||
let exists = fs.path(&path).exists().expect("exists");
|
let_assert!(Ok(exists) = fs.path_exists(&path));
|
||||||
assert!(exists);
|
assert!(exists);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn should_be_false_when_it_does_not_exist() -> TestResult {
|
fn should_be_false_when_it_does_not_exist() -> TestResult {
|
||||||
let fs = fs::temp().expect("temp fs");
|
let fs = fs::temp()?;
|
||||||
let path = fs.base().join("foo");
|
let path = fs.base().join("foo");
|
||||||
let exists = fs.path(&path).exists().expect("exists");
|
let_assert!(Ok(exists) = fs.path_exists(&path));
|
||||||
assert!(!exists);
|
assert!(!exists);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn should_fail_on_path_traversal() -> TestResult {
|
fn should_fail_on_path_traversal() -> TestResult {
|
||||||
let fs = fs::temp().expect("temp fs");
|
let fs = fs::temp()?;
|
||||||
let path = fs.base().join("..").join("foo");
|
let path = fs.base().join("..").join("foo");
|
||||||
let_assert!(
|
let_assert!(
|
||||||
Err(fs::Error::PathTraversal {
|
Err(fs::Error::PathTraversal {
|
||||||
base: _base,
|
base: _base,
|
||||||
path: _path
|
path: _path
|
||||||
}) = fs.path(&path).exists()
|
}) = fs.path_exists(&path)
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -215,20 +198,20 @@ mod path_is_dir {
|
||||||
use super::*;
|
use super::*;
|
||||||
#[test]
|
#[test]
|
||||||
fn should_be_true_when_is_a_dir() -> TestResult {
|
fn should_be_true_when_is_a_dir() -> TestResult {
|
||||||
let fs = fs::temp().expect("temp fs");
|
let fs = fs::temp()?;
|
||||||
let path = fs.base().join("foo");
|
let path = fs.base().join("foo");
|
||||||
fs.dir(&path).create().expect("create");
|
let_assert!(Ok(_) = fs.dir_create(&path));
|
||||||
let is_dir = fs.path(&path).is_dir().expect("is_dir");
|
let_assert!(Ok(is_dir) = fs.path_is_dir(&path));
|
||||||
assert!(is_dir);
|
assert!(is_dir);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn should_be_false_when_is_a_file() -> TestResult {
|
fn should_be_false_when_is_a_file() -> TestResult {
|
||||||
let fs = fs::temp().expect("temp fs");
|
let fs = fs::temp()?;
|
||||||
let path = fs.base().join("foo");
|
let path = fs.base().join("foo");
|
||||||
fs.file(&path).write("bar").expect("write");
|
let_assert!(Ok(_) = fs.file_write(&path, "bar"));
|
||||||
let is_dir = fs.path(&path).is_dir().expect("is_dir");
|
let_assert!(Ok(is_dir) = fs.path_is_dir(&path));
|
||||||
assert!(!is_dir);
|
assert!(!is_dir);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -236,24 +219,24 @@ mod path_is_dir {
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore]
|
#[ignore]
|
||||||
fn should_be_false_when_is_a_link() -> TestResult {
|
fn should_be_false_when_is_a_link() -> TestResult {
|
||||||
let fs = fs::temp().expect("temp fs");
|
let fs = fs::temp()?;
|
||||||
let path = fs.base().join("foo");
|
let path = fs.base().join("foo");
|
||||||
// TODO: (#38) create a link
|
// TODO: (#38) create a link
|
||||||
// let_assert!(Ok(_) = fs.file_write(&path, "bar"));
|
// let_assert!(Ok(_) = fs.file_write(&path, "bar"));
|
||||||
let is_dir = fs.path(&path).is_dir().expect("is_dir");
|
let_assert!(Ok(is_dir) = fs.path_is_dir(&path));
|
||||||
assert!(!is_dir);
|
assert!(!is_dir);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn should_fail_on_path_traversal() -> TestResult {
|
fn should_fail_on_path_traversal() -> TestResult {
|
||||||
let fs = fs::temp().expect("temp fs");
|
let fs = fs::temp()?;
|
||||||
let path = fs.base().join("..").join("foo");
|
let path = fs.base().join("..").join("foo");
|
||||||
let_assert!(
|
let_assert!(
|
||||||
Err(fs::Error::PathTraversal {
|
Err(fs::Error::PathTraversal {
|
||||||
base: _base,
|
base: _base,
|
||||||
path: _path
|
path: _path
|
||||||
}) = fs.dir(&path).is_dir()
|
}) = fs.path_is_dir(&path)
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -264,21 +247,21 @@ mod path_is_file {
|
||||||
use super::*;
|
use super::*;
|
||||||
#[test]
|
#[test]
|
||||||
fn should_be_true_when_is_a_file() -> TestResult {
|
fn should_be_true_when_is_a_file() -> TestResult {
|
||||||
let fs = fs::temp().expect("temp fs");
|
let fs = fs::temp()?;
|
||||||
let path = fs.base().join("foo");
|
let path = fs.base().join("foo");
|
||||||
fs.file(&path).write("bar").expect("write");
|
let_assert!(Ok(_) = fs.file_write(&path, "bar"));
|
||||||
|
|
||||||
let is_file = fs.path(&path).is_file().expect("is_file");
|
let_assert!(Ok(is_file) = fs.path_is_file(&path));
|
||||||
assert!(is_file);
|
assert!(is_file);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn should_be_false_when_is_a_dir() -> TestResult {
|
fn should_be_false_when_is_a_dir() -> TestResult {
|
||||||
let fs = fs::temp().expect("temp fs");
|
let fs = fs::temp()?;
|
||||||
let path = fs.base().join("foo");
|
let path = fs.base().join("foo");
|
||||||
fs.dir(&path).create().expect("create");
|
let_assert!(Ok(_) = fs.dir_create(&path));
|
||||||
let is_file = fs.path(&path).is_file().expect("is_file");
|
let_assert!(Ok(is_file) = fs.path_is_file(&path));
|
||||||
assert!(!is_file);
|
assert!(!is_file);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -286,24 +269,24 @@ mod path_is_file {
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore]
|
#[ignore]
|
||||||
fn should_be_false_when_is_a_link() -> TestResult {
|
fn should_be_false_when_is_a_link() -> TestResult {
|
||||||
let fs = fs::temp().expect("temp fs");
|
let fs = fs::temp()?;
|
||||||
let path = fs.base().join("foo");
|
let path = fs.base().join("foo");
|
||||||
// TODO: (#38) create a link
|
// TODO: (#38) create a link
|
||||||
// let_assert!(Ok(_) = fs.file_write(&path, "bar"));
|
// let_assert!(Ok(_) = fs.file_write(&path, "bar"));
|
||||||
let is_file = fs.path(&path).is_file().expect("is_file");
|
let_assert!(Ok(is_file) = fs.path_is_file(&path));
|
||||||
assert!(!is_file);
|
assert!(!is_file);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn should_fail_on_path_traversal() -> TestResult {
|
fn should_fail_on_path_traversal() -> TestResult {
|
||||||
let fs = fs::temp().expect("temp fs");
|
let fs = fs::temp()?;
|
||||||
let path = fs.base().join("..").join("foo");
|
let path = fs.base().join("..").join("foo");
|
||||||
let_assert!(
|
let_assert!(
|
||||||
Err(fs::Error::PathTraversal {
|
Err(fs::Error::PathTraversal {
|
||||||
base: _base,
|
base: _base,
|
||||||
path: _path
|
path: _path
|
||||||
}) = fs.file(&path).is_file()
|
}) = fs.path_is_file(&path)
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
Loading…
Reference in a new issue