use std::{cmp::Ordering, fmt, path::Path};
use super::entry_iter::EntryIter;
use crate::{
errors::*,
sys::{Entry, VfsEntry},
trying,
};
pub(crate) const DEFAULT_MAX_DESCRIPTORS: u16 = 50;
pub struct Entries {
pub(crate) root: VfsEntry,
pub(crate) dirs: bool,
pub(crate) files: bool,
pub(crate) follow: bool,
pub(crate) min_depth: usize,
pub(crate) max_depth: usize,
pub(crate) max_descriptors: u16,
pub(crate) dirs_first: bool,
pub(crate) files_first: bool,
pub(crate) sort_by_name: bool,
pub(crate) contents_first: bool,
#[allow(clippy::type_complexity)]
pub(crate) pre_op: Option<Box<dyn FnMut(&VfsEntry) -> RvResult<()> + Send + Sync + 'static>>,
#[allow(clippy::type_complexity)]
pub(crate) sort: Option<Box<dyn Fn(&VfsEntry, &VfsEntry) -> Ordering + Send + Sync + 'static>>,
#[allow(clippy::type_complexity)]
pub(crate) iter_from: Box<dyn Fn(&Path, bool) -> RvResult<EntryIter> + Send + Sync + 'static>,
}
impl Entries {
pub fn dirs(mut self) -> Self {
self.dirs = true;
self.files = false;
self
}
pub fn files(mut self) -> Self {
self.dirs = false;
self.files = true;
self
}
pub fn follow(mut self, yes: bool) -> Self {
self.follow = yes;
self
}
pub fn min_depth(mut self, min: usize) -> Self {
self.min_depth = min;
if self.min_depth > self.max_depth {
self.min_depth = self.max_depth;
}
self
}
pub fn max_depth(mut self, max: usize) -> Self {
self.max_depth = max;
if self.max_depth < self.min_depth {
self.max_depth = self.min_depth;
}
self
}
pub fn pre_op(mut self, op: impl FnMut(&VfsEntry) -> RvResult<()> + Send + Sync + 'static) -> Self {
self.pre_op = Some(Box::new(op));
self
}
pub fn dirs_first(mut self) -> Self {
self.dirs_first = true;
self.sort(|x, y| x.file_name().cmp(&y.file_name()))
}
pub fn files_first(mut self) -> Self {
self.files_first = true;
self.sort(|x, y| x.file_name().cmp(&y.file_name()))
}
pub fn contents_first(mut self) -> Self {
self.contents_first = true;
self
}
pub fn sort_by_name(mut self) -> Self {
self.sort_by_name = true;
self.sort(|x, y| x.file_name().cmp(&y.file_name()))
}
pub fn sort(mut self, cmp: impl Fn(&VfsEntry, &VfsEntry) -> Ordering + Send + Sync + 'static) -> Self {
self.sort = Some(Box::new(cmp));
self
}
}
impl fmt::Debug for Entries {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
f.debug_struct("Entries")
.field("root", &self.root)
.field("dirs", &self.dirs)
.field("files", &self.files)
.field("follow", &self.follow)
.field("min_depth", &self.min_depth)
.field("max_depth", &self.max_depth)
.field("max_descriptors", &self.max_descriptors)
.field("dirs_first", &self.dirs_first)
.field("files_first", &self.files_first)
.field("contents_first", &self.contents_first)
.field("sort_by_name", &self.sort_by_name)
.finish()
}
}
impl IntoIterator for Entries {
type IntoIter = EntriesIter;
type Item = RvResult<VfsEntry>;
fn into_iter(self) -> EntriesIter {
let mut iter = EntriesIter {
opts: self,
started: false,
open_descriptors: 0,
filter: None,
deferred: vec![],
iters: vec![],
};
if iter.opts.files {
iter.filter = Some(Box::new(|x: &VfsEntry| -> bool { x.is_file() }));
} else if iter.opts.dirs {
iter.filter = Some(Box::new(|x: &VfsEntry| -> bool { x.is_dir() }));
}
iter
}
}
pub struct EntriesIter {
opts: Entries,
started: bool,
open_descriptors: u16,
iters: Vec<EntryIter>,
deferred: Vec<VfsEntry>,
#[allow(clippy::type_complexity)]
filter: Option<Box<dyn FnMut(&VfsEntry) -> bool>>,
}
impl EntriesIter {
fn process(&mut self, entry: VfsEntry) -> Option<RvResult<VfsEntry>> {
let depth = self.iters.len();
if entry.is_dir() && (!entry.is_symlink() || self.opts.follow) {
if entry.is_symlink() && self.iters.iter().any(|x| x.path() == entry.path()) {
return Some(Err(PathError::link_looping(entry.path()).into()));
}
if self.iters.len() < self.opts.max_depth {
if let Some(pre_op) = &mut self.opts.pre_op {
trying!((pre_op)(&entry));
}
self.iters.push(trying!((self.opts.iter_from)(entry.path(), self.opts.follow)));
if self.opts.sort.is_some() || (self.open_descriptors + 1 > self.opts.max_descriptors) {
if let Some(sort) = &self.opts.sort {
if self.opts.dirs_first {
self.iters.last_mut().unwrap().dirs_first(sort);
} else if self.opts.files_first {
self.iters.last_mut().unwrap().files_first(sort);
} else {
self.iters.last_mut().unwrap().sort(sort);
}
} else {
self.iters.last_mut().unwrap().cache();
}
} else {
self.open_descriptors += 1;
}
}
}
if depth < self.opts.min_depth {
return None;
}
if entry.is_dir() && self.opts.contents_first {
self.deferred.push(entry);
return None;
}
if let Some(filter) = &mut self.filter {
if !(filter)(&entry) {
return None;
}
}
Some(Ok(entry))
}
pub fn filter_p(mut self, predicate: impl FnMut(&VfsEntry) -> bool + 'static) -> Self {
self.filter = Some(Box::new(predicate));
self
}
}
impl Iterator for EntriesIter {
type Item = RvResult<VfsEntry>;
fn next(&mut self) -> Option<RvResult<VfsEntry>> {
if !self.started {
self.started = true;
let result = self.process(self.opts.root.clone().follow(self.opts.follow));
if result.is_some() {
return result;
}
}
while !self.iters.is_empty() {
if self.opts.contents_first && self.iters.len() < self.deferred.len() {
if let Some(entry) = self.deferred.pop() {
return Some(Ok(entry));
}
}
match self.iters.last_mut().unwrap().next() {
Some(Ok(entry)) => match self.process(entry) {
Some(result) => return Some(result),
None => continue, },
Some(Err(err)) => return Some(Err(err)),
None => {
if let Some(iter) = self.iters.pop() {
if !iter.cached() {
self.open_descriptors -= 1;
}
}
},
};
}
if self.opts.contents_first && self.iters.len() < self.deferred.len() {
if let Some(entry) = self.deferred.pop() {
return Some(Ok(entry));
}
}
None
}
}
#[cfg(test)]
mod tests {
use crate::prelude::*;
fn assert_iter_eq(iter: EntriesIter, paths: Vec<&PathBuf>) {
let mut entries = Vec::new();
for entry in iter {
entries.push(entry.unwrap().path().to_path_buf());
}
assert_eq!(entries.len(), paths.len());
for path in paths.iter() {
assert!(entries.contains(path));
}
}
#[test]
fn test_entries_debug() {
let vfs = Vfs::memfs();
let entries = vfs.entries(vfs.root()).unwrap();
assert_eq!(format!("{:?}", &entries), format!("{:?}", &entries));
}
#[test]
fn test_vfs_dirs() {
test_dirs(assert_vfs_setup!(Vfs::memfs()));
test_dirs(assert_vfs_setup!(Vfs::stdfs()));
}
fn test_dirs((vfs, tmpdir): (Vfs, PathBuf)) {
let dir1 = tmpdir.mash("zdir");
let file1 = tmpdir.mash("file");
assert_vfs_mkdir_p!(vfs, &dir1);
assert_vfs_mkfile!(vfs, &file1);
let mut iter = vfs.entries(&tmpdir).unwrap().sort_by_name().into_iter();
assert_eq!(iter.next().unwrap().unwrap().path(), &tmpdir);
assert_eq!(iter.next().unwrap().unwrap().path(), &file1);
assert_eq!(iter.next().unwrap().unwrap().path(), &dir1);
assert!(iter.next().is_none());
let mut iter = vfs.entries(&tmpdir).unwrap().dirs().sort_by_name().into_iter();
assert_eq!(iter.next().unwrap().unwrap().path(), &tmpdir);
assert_eq!(iter.next().unwrap().unwrap().path(), &dir1);
assert!(iter.next().is_none());
assert_vfs_remove_all!(vfs, &tmpdir);
}
#[test]
fn test_vfs_files() {
test_files(assert_vfs_setup!(Vfs::memfs()));
test_files(assert_vfs_setup!(Vfs::stdfs()));
}
fn test_files((vfs, tmpdir): (Vfs, PathBuf)) {
let dir1 = tmpdir.mash("zdir");
let file1 = tmpdir.mash("file");
assert_vfs_mkdir_p!(vfs, &dir1);
assert_vfs_mkfile!(vfs, &file1);
let mut iter = vfs.entries(&tmpdir).unwrap().sort_by_name().into_iter();
assert_eq!(iter.next().unwrap().unwrap().path(), &tmpdir);
assert_eq!(iter.next().unwrap().unwrap().path(), &file1);
assert_eq!(iter.next().unwrap().unwrap().path(), &dir1);
assert!(iter.next().is_none());
let mut iter = vfs.entries(&tmpdir).unwrap().files().sort_by_name().into_iter();
assert_eq!(iter.next().unwrap().unwrap().path(), &file1);
assert!(iter.next().is_none());
assert_vfs_remove_all!(vfs, &tmpdir);
}
#[test]
fn test_vfs_follow() {
test_follow(assert_vfs_setup!(Vfs::memfs()));
test_follow(assert_vfs_setup!(Vfs::stdfs()));
}
fn test_follow((vfs, tmpdir): (Vfs, PathBuf)) {
let dir1 = tmpdir.mash("dir1");
let file1 = dir1.mash("file1");
let link1 = tmpdir.mash("link1");
assert_vfs_mkdir_p!(vfs, &dir1);
assert_vfs_mkfile!(vfs, &file1);
assert_vfs_symlink!(vfs, &link1, &dir1);
let mut iter = vfs.entries(&link1).unwrap().into_iter();
assert_eq!(iter.next().unwrap().unwrap().path(), &link1);
assert!(iter.next().is_none());
let mut iter = vfs.entries(&link1).unwrap().follow(true).sort_by_name().into_iter();
assert_eq!(iter.next().unwrap().unwrap().path(), &dir1);
assert_eq!(iter.next().unwrap().unwrap().path(), &file1);
assert!(iter.next().is_none());
assert_vfs_remove_all!(vfs, &tmpdir);
}
#[test]
fn test_vfs_depth() {
test_depth(assert_vfs_setup!(Vfs::memfs()));
test_depth(assert_vfs_setup!(Vfs::stdfs()));
}
fn test_depth((vfs, tmpdir): (Vfs, PathBuf)) {
let dir1 = tmpdir.mash("dir1");
let dir1file1 = dir1.mash("file1");
let file1 = tmpdir.mash("file1");
let dir2 = dir1.mash("dir2");
let dir2file1 = dir2.mash("file1");
assert_vfs_mkdir_p!(vfs, &dir2);
assert_vfs_mkfile!(vfs, &dir1file1);
assert_vfs_mkfile!(vfs, &dir2file1);
assert_vfs_mkfile!(vfs, &file1);
let mut iter = vfs.entries(&tmpdir).unwrap().max_depth(0).into_iter();
assert_eq!(iter.next().unwrap().unwrap().path(), tmpdir);
assert!(iter.next().is_none());
let iter = vfs.entries(&tmpdir).unwrap().max_depth(1).into_iter();
assert_iter_eq(iter, vec![&tmpdir, &file1, &dir1]);
let iter = vfs.entries(&tmpdir).unwrap().max_depth(2).into_iter();
assert_iter_eq(iter, vec![&tmpdir, &file1, &dir1, &dir2, &dir1file1]);
let iter = vfs.entries(&tmpdir).unwrap().min_depth(1).into_iter();
assert_iter_eq(iter, vec![&file1, &dir1, &dir2, &dir1file1, &dir2file1]);
let iter = vfs.entries(&tmpdir).unwrap().min_depth(1).max_depth(1).into_iter();
assert_iter_eq(iter, vec![&file1, &dir1]);
let iter = vfs.entries(&tmpdir).unwrap().min_depth(1).max_depth(2).into_iter();
assert_iter_eq(iter, vec![&file1, &dir1, &dir2, &dir1file1]);
let iter = vfs.entries(&tmpdir).unwrap().min_depth(2).max_depth(1).into_iter();
assert_eq!(iter.opts.min_depth, 2);
assert_eq!(iter.opts.max_depth, 2);
assert_iter_eq(iter, vec![&dir2, &dir1file1]);
let iter = vfs.entries(&tmpdir).unwrap().max_depth(1).min_depth(2).into_iter();
assert_eq!(iter.opts.min_depth, 1);
assert_eq!(iter.opts.max_depth, 1);
assert_iter_eq(iter, vec![&file1, &dir1]);
assert_vfs_remove_all!(vfs, &tmpdir);
}
#[test]
fn test_vfs_contents_first() {
test_contents_first(assert_vfs_setup!(Vfs::memfs()));
test_contents_first(assert_vfs_setup!(Vfs::stdfs()));
}
fn test_contents_first((vfs, tmpdir): (Vfs, PathBuf)) {
let dir1 = tmpdir.mash("dir1");
let file1 = dir1.mash("file1");
let dir2 = dir1.mash("dir2");
let file2 = dir2.mash("file2");
let file3 = tmpdir.mash("file3");
let link1 = tmpdir.mash("link1");
assert_vfs_mkdir_p!(vfs, &dir2);
assert_vfs_mkfile!(vfs, &file1);
assert_vfs_mkfile!(vfs, &file2);
assert_vfs_mkfile!(vfs, &file3);
assert_vfs_symlink!(vfs, &link1, &file3);
let iter = vfs.entries(&tmpdir).unwrap().contents_first().into_iter();
assert_iter_eq(iter, vec![&link1, &file3, &file2, &dir2, &file1, &dir1, &tmpdir]);
let mut iter = vfs.entries(&tmpdir).unwrap().contents_first().sort_by_name().into_iter();
assert_eq!(iter.next().unwrap().unwrap().path(), file2);
assert_eq!(iter.next().unwrap().unwrap().path(), dir2);
assert_eq!(iter.next().unwrap().unwrap().path(), file1);
assert_eq!(iter.next().unwrap().unwrap().path(), dir1);
assert_eq!(iter.next().unwrap().unwrap().path(), file3);
assert_eq!(iter.next().unwrap().unwrap().path(), link1);
assert_eq!(iter.next().unwrap().unwrap().path(), tmpdir);
assert!(iter.next().is_none());
assert_vfs_remove_all!(vfs, &tmpdir);
}
#[test]
fn test_vfs_sort() {
test_sort(assert_vfs_setup!(Vfs::memfs()));
test_sort(assert_vfs_setup!(Vfs::stdfs()));
}
fn test_sort((vfs, tmpdir): (Vfs, PathBuf)) {
let zdir1 = tmpdir.mash("zdir1");
let dir1file1 = zdir1.mash("file1");
let dir1file2 = zdir1.mash("file2");
let zdir2 = tmpdir.mash("zdir2");
let dir2file1 = zdir2.mash("file1");
let dir2file2 = zdir2.mash("file2");
let file1 = tmpdir.mash("file1");
let file2 = tmpdir.mash("file2");
assert_vfs_mkdir_p!(vfs, &zdir1);
assert_vfs_mkdir_p!(vfs, &zdir2);
assert_vfs_mkfile!(vfs, &dir1file1);
assert_vfs_mkfile!(vfs, &dir1file2);
assert_vfs_mkfile!(vfs, &dir2file1);
assert_vfs_mkfile!(vfs, &dir2file2);
assert_vfs_mkfile!(vfs, &file1);
assert_vfs_mkfile!(vfs, &file2);
let iter = vfs.entries(&tmpdir).unwrap().into_iter();
assert_iter_eq(
iter,
vec![
&tmpdir, &file2, &zdir1, &dir1file2, &dir1file1, &file1, &zdir2, &dir2file2, &dir2file1,
],
);
let mut iter = vfs.entries(&tmpdir).unwrap().sort(|x, y| x.file_name().cmp(&y.file_name())).into_iter();
assert_eq!(iter.next().unwrap().unwrap().path(), tmpdir);
assert_eq!(iter.next().unwrap().unwrap().path(), file1);
assert_eq!(iter.next().unwrap().unwrap().path(), file2);
assert_eq!(iter.next().unwrap().unwrap().path(), zdir1);
assert_eq!(iter.next().unwrap().unwrap().path(), dir1file1);
assert_eq!(iter.next().unwrap().unwrap().path(), dir1file2);
assert_eq!(iter.next().unwrap().unwrap().path(), zdir2);
assert_eq!(iter.next().unwrap().unwrap().path(), dir2file1);
assert_eq!(iter.next().unwrap().unwrap().path(), dir2file2);
assert!(iter.next().is_none());
let mut iter = vfs.entries(&tmpdir).unwrap().sort_by_name().into_iter();
assert_eq!(iter.next().unwrap().unwrap().path(), tmpdir);
assert_eq!(iter.next().unwrap().unwrap().path(), file1);
assert_eq!(iter.next().unwrap().unwrap().path(), file2);
assert_eq!(iter.next().unwrap().unwrap().path(), zdir1);
assert_eq!(iter.next().unwrap().unwrap().path(), dir1file1);
assert_eq!(iter.next().unwrap().unwrap().path(), dir1file2);
assert_eq!(iter.next().unwrap().unwrap().path(), zdir2);
assert_eq!(iter.next().unwrap().unwrap().path(), dir2file1);
assert_eq!(iter.next().unwrap().unwrap().path(), dir2file2);
assert!(iter.next().is_none());
let zdir3 = zdir1.mash("zdir3");
let dir3file1 = zdir3.mash("file1");
let dir3file2 = zdir3.mash("file2");
assert_vfs_mkdir_p!(vfs, &zdir3);
assert_vfs_mkfile!(vfs, &dir3file1);
assert_vfs_mkfile!(vfs, &dir3file2);
let mut iter = vfs.entries(&tmpdir).unwrap().dirs_first().into_iter();
assert_eq!(iter.next().unwrap().unwrap().path(), tmpdir);
assert_eq!(iter.next().unwrap().unwrap().path(), zdir1);
assert_eq!(iter.next().unwrap().unwrap().path(), zdir3);
assert_eq!(iter.next().unwrap().unwrap().path(), dir3file1);
assert_eq!(iter.next().unwrap().unwrap().path(), dir3file2);
assert_eq!(iter.next().unwrap().unwrap().path(), dir1file1);
assert_eq!(iter.next().unwrap().unwrap().path(), dir1file2);
assert_eq!(iter.next().unwrap().unwrap().path(), zdir2);
assert_eq!(iter.next().unwrap().unwrap().path(), dir2file1);
assert_eq!(iter.next().unwrap().unwrap().path(), dir2file2);
assert_eq!(iter.next().unwrap().unwrap().path(), file1);
assert_eq!(iter.next().unwrap().unwrap().path(), file2);
assert!(iter.next().is_none());
let mut iter = vfs.entries(&tmpdir).unwrap().files_first().into_iter();
assert_eq!(iter.next().unwrap().unwrap().path(), tmpdir);
assert_eq!(iter.next().unwrap().unwrap().path(), file1);
assert_eq!(iter.next().unwrap().unwrap().path(), file2);
assert_eq!(iter.next().unwrap().unwrap().path(), zdir1);
assert_eq!(iter.next().unwrap().unwrap().path(), dir1file1);
assert_eq!(iter.next().unwrap().unwrap().path(), dir1file2);
assert_eq!(iter.next().unwrap().unwrap().path(), zdir3);
assert_eq!(iter.next().unwrap().unwrap().path(), dir3file1);
assert_eq!(iter.next().unwrap().unwrap().path(), dir3file2);
assert_eq!(iter.next().unwrap().unwrap().path(), zdir2);
assert_eq!(iter.next().unwrap().unwrap().path(), dir2file1);
assert_eq!(iter.next().unwrap().unwrap().path(), dir2file2);
assert!(iter.next().is_none());
let mut iter =
vfs.entries(&tmpdir).unwrap().files_first().sort(|x, y| y.file_name().cmp(&x.file_name())).into_iter();
assert_eq!(iter.next().unwrap().unwrap().path(), tmpdir);
assert_eq!(iter.next().unwrap().unwrap().path(), file2);
assert_eq!(iter.next().unwrap().unwrap().path(), file1);
assert_eq!(iter.next().unwrap().unwrap().path(), zdir2);
assert_eq!(iter.next().unwrap().unwrap().path(), dir2file2);
assert_eq!(iter.next().unwrap().unwrap().path(), dir2file1);
assert_eq!(iter.next().unwrap().unwrap().path(), zdir1);
assert_eq!(iter.next().unwrap().unwrap().path(), dir1file2);
assert_eq!(iter.next().unwrap().unwrap().path(), dir1file1);
assert_eq!(iter.next().unwrap().unwrap().path(), zdir3);
assert_eq!(iter.next().unwrap().unwrap().path(), dir3file2);
assert_eq!(iter.next().unwrap().unwrap().path(), dir3file1);
assert!(iter.next().is_none());
assert_vfs_remove_all!(vfs, &tmpdir);
}
#[test]
fn test_vfs_max_descriptors() {
test_max_descriptors(assert_vfs_setup!(Vfs::memfs()));
test_max_descriptors(assert_vfs_setup!(Vfs::stdfs()));
}
fn test_max_descriptors((vfs, tmpdir): (Vfs, PathBuf)) {
let dir1 = tmpdir.mash("dir1");
let file1 = dir1.mash("file1");
let dir2 = dir1.mash("dir2");
let file2 = dir2.mash("file2");
let dir3 = dir2.mash("dir3");
let file3 = dir3.mash("file3");
assert_vfs_mkdir_p!(vfs, &dir3);
assert_vfs_mkfile!(vfs, &file1);
assert_vfs_mkfile!(vfs, &file2);
assert_vfs_mkfile!(vfs, &file3);
let iter = vfs.entries(&tmpdir).unwrap().into_iter();
assert_iter_eq(iter, vec![&tmpdir, &dir1, &dir2, &file2, &dir3, &file3, &file1]);
let mut paths = vfs.entries(&tmpdir).unwrap();
paths.max_descriptors = 1;
let iter = paths.into_iter();
assert_iter_eq(iter, vec![&tmpdir, &dir1, &dir2, &file2, &dir3, &file3, &file1]);
assert_vfs_remove_all!(vfs, &tmpdir);
}
#[test]
fn test_vfs_loop_detection() {
test_loop_detection(assert_vfs_setup!(Vfs::memfs()));
test_loop_detection(assert_vfs_setup!(Vfs::stdfs()));
}
fn test_loop_detection((vfs, tmpdir): (Vfs, PathBuf)) {
let dir1 = tmpdir.mash("dir1");
let dir2 = dir1.mash("dir2");
let link1 = dir2.mash("link1");
assert_vfs_mkdir_p!(vfs, &dir2);
assert_vfs_symlink!(vfs, &link1, &dir1);
let iter = vfs.entries(&tmpdir).unwrap().into_iter();
assert_iter_eq(iter, vec![&tmpdir, &dir1, &dir2, &link1]);
let mut iter = vfs.entries(&tmpdir).unwrap().follow(true).into_iter();
assert_eq!(iter.next().unwrap().unwrap().path(), tmpdir);
assert_eq!(iter.next().unwrap().unwrap().path(), dir1);
assert_eq!(iter.next().unwrap().unwrap().path(), dir2);
assert_eq!(iter.next().unwrap().unwrap_err().to_string(), PathError::link_looping(dir1).to_string());
assert!(iter.next().is_none());
assert_vfs_remove_all!(vfs, &tmpdir);
}
#[test]
fn test_vfs_filter() {
test_filter(assert_vfs_setup!(Vfs::memfs()));
test_filter(assert_vfs_setup!(Vfs::stdfs()));
}
fn test_filter((vfs, tmpdir): (Vfs, PathBuf)) {
let dir1 = tmpdir.mash("dir1");
let file1 = dir1.mash("file1");
let dir2 = dir1.mash("dir2");
let file2 = dir2.mash("file2");
let file3 = tmpdir.mash("file3");
let link1 = tmpdir.mash("link1");
let link2 = tmpdir.mash("link2");
assert_vfs_mkdir_p!(vfs, &dir2);
assert_vfs_mkfile!(vfs, &file1);
assert_vfs_mkfile!(vfs, &file2);
assert_vfs_mkfile!(vfs, &file3);
assert_vfs_symlink!(vfs, &link2, &dir2);
assert_vfs_symlink!(vfs, &link1, &file1);
let iter = vfs.entries(&tmpdir).unwrap().files().into_iter();
assert_iter_eq(iter, vec![&link1, &file3, &file2, &file1]);
let iter = vfs.entries(&tmpdir).unwrap().dirs().into_iter();
assert_iter_eq(iter, vec![&tmpdir, &link2, &dir1, &dir2]);
let iter = vfs.entries(&tmpdir).unwrap().into_iter().filter_p(|x| x.is_symlink());
assert_iter_eq(iter, vec![&link1, &link2]);
let iter = vfs.entries(&tmpdir).unwrap().into_iter().filter_p(|x| x.path().has_suffix("1"));
assert_iter_eq(iter, vec![&link1, &dir1, &file1]);
assert_vfs_remove_all!(vfs, &tmpdir);
}
#[test]
fn test_vfs_multiple() {
test_multiple(assert_vfs_setup!(Vfs::memfs()));
test_multiple(assert_vfs_setup!(Vfs::stdfs()));
}
fn test_multiple((vfs, tmpdir): (Vfs, PathBuf)) {
let dir1 = tmpdir.mash("dir1");
let file1 = dir1.mash("file1");
let dir2 = dir1.mash("dir2");
let file2 = dir2.mash("file2");
let file3 = tmpdir.mash("file3");
let link1 = tmpdir.mash("link1");
assert_vfs_mkdir_p!(vfs, &dir2);
assert_vfs_mkfile!(vfs, &file1);
assert_vfs_mkfile!(vfs, &file2);
assert_vfs_mkfile!(vfs, &file3);
assert_vfs_symlink!(vfs, &link1, &file3);
let iter = vfs.entries(&tmpdir).unwrap().into_iter();
assert_iter_eq(iter, vec![&tmpdir, &file3, &dir1, &dir2, &file2, &file1, &link1]);
assert_vfs_remove_all!(vfs, &tmpdir);
}
#[test]
fn test_vfs_single() {
test_single(assert_vfs_setup!(Vfs::memfs()));
test_single(assert_vfs_setup!(Vfs::stdfs()));
}
fn test_single((vfs, tmpdir): (Vfs, PathBuf)) {
let file1 = tmpdir.mash("file1");
let mut iter = vfs.entries(&tmpdir).unwrap().into_iter();
assert_eq!(iter.next().unwrap().unwrap().path(), tmpdir);
assert!(iter.next().is_none());
assert_vfs_mkfile!(vfs, &file1);
let mut iter = vfs.entries(&file1).unwrap().into_iter();
assert_eq!(iter.next().unwrap().unwrap().path(), file1);
assert!(iter.next().is_none());
assert_vfs_remove_all!(vfs, &tmpdir);
}
}