Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/windirstat/walkdir.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/tests/util.rs')
-rw-r--r--src/tests/util.rs251
1 files changed, 251 insertions, 0 deletions
diff --git a/src/tests/util.rs b/src/tests/util.rs
new file mode 100644
index 0000000..968ee7c
--- /dev/null
+++ b/src/tests/util.rs
@@ -0,0 +1,251 @@
+use std::env;
+use std::error;
+use std::fs::{self, File};
+use std::io;
+use std::path::{Path, PathBuf};
+use std::result;
+
+use {DirEntry, Error};
+
+/// Create an error from a format!-like syntax.
+#[macro_export]
+macro_rules! err {
+ ($($tt:tt)*) => {
+ Box::<error::Error + Send + Sync>::from(format!($($tt)*))
+ }
+}
+
+/// A convenient result type alias.
+pub type Result<T> = result::Result<T, Box<error::Error + Send + Sync>>;
+
+/// The result of running a recursive directory iterator on a single directory.
+#[derive(Debug)]
+pub struct RecursiveResults {
+ ents: Vec<DirEntry>,
+ errs: Vec<Error>,
+}
+
+impl RecursiveResults {
+ /// Return all of the errors encountered during traversal.
+ pub fn errs(&self) -> &[Error] {
+ &self.errs
+ }
+
+ /// Assert that no errors have occurred.
+ pub fn assert_no_errors(&self) {
+ assert!(
+ self.errs.is_empty(),
+ "expected to find no errors, but found: {:?}",
+ self.errs
+ );
+ }
+
+ /// Return all the successfully retrieved directory entries in the order
+ /// in which they were retrieved.
+ pub fn ents(&self) -> &[DirEntry] {
+ &self.ents
+ }
+
+ /// Return all paths from all successfully retrieved directory entries.
+ ///
+ /// This does not include paths that correspond to an error.
+ pub fn paths(&self) -> Vec<PathBuf> {
+ self.ents.iter().map(|d| d.path().to_path_buf()).collect()
+ }
+
+ /// Return all the successfully retrieved directory entries, sorted
+ /// lexicographically by their full file path.
+ pub fn sorted_ents(&self) -> Vec<DirEntry> {
+ let mut ents = self.ents.clone();
+ ents.sort_by(|e1, e2| e1.path().cmp(e2.path()));
+ ents
+ }
+
+ /// Return all paths from all successfully retrieved directory entries,
+ /// sorted lexicographically.
+ ///
+ /// This does not include paths that correspond to an error.
+ pub fn sorted_paths(&self) -> Vec<PathBuf> {
+ self.sorted_ents().into_iter().map(|d| d.into_path()).collect()
+ }
+}
+
+/// A helper for managing a directory in which to run tests.
+///
+/// When manipulating paths within this directory, paths are interpreted
+/// relative to this directory.
+#[derive(Debug)]
+pub struct Dir {
+ dir: TempDir,
+}
+
+impl Dir {
+ /// Create a new empty temporary directory.
+ pub fn tmp() -> Dir {
+ let dir = TempDir::new().unwrap();
+ Dir { dir }
+ }
+
+ /// Return the path to this directory.
+ pub fn path(&self) -> &Path {
+ self.dir.path()
+ }
+
+ /// Return a path joined to the path to this directory.
+ pub fn join<P: AsRef<Path>>(&self, path: P) -> PathBuf {
+ self.path().join(path)
+ }
+
+ /// Run the given iterator and return the result as a distinct collection
+ /// of directory entries and errors.
+ pub fn run_recursive<I>(
+ &self,
+ it: I,
+ ) -> RecursiveResults
+ where I: IntoIterator<Item=result::Result<DirEntry, Error>>
+ {
+ let mut results = RecursiveResults {
+ ents: vec![],
+ errs: vec![],
+ };
+ for result in it {
+ match result {
+ Ok(ent) => results.ents.push(ent),
+ Err(err) => results.errs.push(err),
+ }
+ }
+ results
+ }
+
+ /// Create a directory at the given path, while creating all intermediate
+ /// directories as needed.
+ pub fn mkdirp<P: AsRef<Path>>(&self, path: P) {
+ let full = self.join(path);
+ fs::create_dir_all(&full)
+ .map_err(|e| {
+ err!("failed to create directory {}: {}", full.display(), e)
+ })
+ .unwrap();
+ }
+
+ /// Create an empty file at the given path. All ancestor directories must
+ /// already exists.
+ pub fn touch<P: AsRef<Path>>(&self, path: P) {
+ let full = self.join(path);
+ File::create(&full)
+ .map_err(|e| {
+ err!("failed to create file {}: {}", full.display(), e)
+ })
+ .unwrap();
+ }
+
+ /// Create empty files at the given paths. All ancestor directories must
+ /// already exists.
+ pub fn touch_all<P: AsRef<Path>>(&self, paths: &[P]) {
+ for p in paths {
+ self.touch(p);
+ }
+ }
+
+ /// Create a file symlink to the given src with the given link name.
+ pub fn symlink_file<P1: AsRef<Path>, P2: AsRef<Path>>(
+ &self,
+ src: P1,
+ link_name: P2,
+ ) {
+ #[cfg(windows)]
+ fn imp(src: &Path, link_name: &Path) -> io::Result<()> {
+ use std::os::windows::fs::symlink_file;
+ symlink_file(src, link_name)
+ }
+
+ #[cfg(unix)]
+ fn imp(src: &Path, link_name: &Path) -> io::Result<()> {
+ use std::os::unix::fs::symlink;
+ symlink(src, link_name)
+ }
+
+ let (src, link_name) = (self.join(src), self.join(link_name));
+ imp(&src, &link_name)
+ .map_err(|e| {
+ err!(
+ "failed to symlink file {} with target {}: {}",
+ src.display(), link_name.display(), e
+ )
+ })
+ .unwrap()
+ }
+
+ /// Create a directory symlink to the given src with the given link name.
+ pub fn symlink_dir<P1: AsRef<Path>, P2: AsRef<Path>>(
+ &self,
+ src: P1,
+ link_name: P2,
+ ) {
+ #[cfg(windows)]
+ fn imp(src: &Path, link_name: &Path) -> io::Result<()> {
+ use std::os::windows::fs::symlink_dir;
+ symlink_dir(src, link_name)
+ }
+
+ #[cfg(unix)]
+ fn imp(src: &Path, link_name: &Path) -> io::Result<()> {
+ use std::os::unix::fs::symlink;
+ symlink(src, link_name)
+ }
+
+ let (src, link_name) = (self.join(src), self.join(link_name));
+ imp(&src, &link_name)
+ .map_err(|e| {
+ err!(
+ "failed to symlink directory {} with target {}: {}",
+ src.display(), link_name.display(), e
+ )
+ })
+ .unwrap()
+ }
+}
+
+/// A simple wrapper for creating a temporary directory that is automatically
+/// deleted when it's dropped.
+///
+/// We use this in lieu of tempfile because tempfile brings in too many
+/// dependencies.
+#[derive(Debug)]
+pub struct TempDir(PathBuf);
+
+impl Drop for TempDir {
+ fn drop(&mut self) {
+ fs::remove_dir_all(&self.0).unwrap();
+ }
+}
+
+impl TempDir {
+ /// Create a new empty temporary directory under the system's configured
+ /// temporary directory.
+ pub fn new() -> Result<TempDir> {
+ use std::sync::atomic::{AtomicUsize, Ordering};
+
+ static TRIES: usize = 100;
+ static COUNTER: AtomicUsize = AtomicUsize::new(0);
+
+ let tmpdir = env::temp_dir();
+ for _ in 0..TRIES {
+ let count = COUNTER.fetch_add(1, Ordering::SeqCst);
+ let path = tmpdir.join("rust-walkdir").join(count.to_string());
+ if path.is_dir() {
+ continue;
+ }
+ fs::create_dir_all(&path).map_err(|e| {
+ err!("failed to create {}: {}", path.display(), e)
+ })?;
+ return Ok(TempDir(path));
+ }
+ Err(err!("failed to create temp dir after {} tries", TRIES))
+ }
+
+ /// Return the underlying path to this temporary directory.
+ pub fn path(&self) -> &Path {
+ &self.0
+ }
+}