From d1b2d29528b7794b41e66fc2136e395a02f8529b Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 30 May 2024 05:59:35 +0200 Subject: Merging upstream version 1.73.0+dfsg1. Signed-off-by: Daniel Baumann --- vendor/fs_extra/.cargo-checksum.json | 1 + vendor/fs_extra/Cargo.toml | 26 + vendor/fs_extra/LICENSE | 21 + vendor/fs_extra/README.md | 134 + vendor/fs_extra/src/dir.rs | 1398 ++++++++++ vendor/fs_extra/src/error.rs | 158 ++ vendor/fs_extra/src/file.rs | 413 +++ vendor/fs_extra/src/lib.rs | 802 ++++++ vendor/fs_extra/tests/dir.rs | 4824 ++++++++++++++++++++++++++++++++++ vendor/fs_extra/tests/file.rs | 1036 ++++++++ vendor/fs_extra/tests/lib.rs | 3883 +++++++++++++++++++++++++++ 11 files changed, 12696 insertions(+) create mode 100644 vendor/fs_extra/.cargo-checksum.json create mode 100644 vendor/fs_extra/Cargo.toml create mode 100644 vendor/fs_extra/LICENSE create mode 100644 vendor/fs_extra/README.md create mode 100644 vendor/fs_extra/src/dir.rs create mode 100644 vendor/fs_extra/src/error.rs create mode 100644 vendor/fs_extra/src/file.rs create mode 100644 vendor/fs_extra/src/lib.rs create mode 100644 vendor/fs_extra/tests/dir.rs create mode 100644 vendor/fs_extra/tests/file.rs create mode 100644 vendor/fs_extra/tests/lib.rs (limited to 'vendor/fs_extra') diff --git a/vendor/fs_extra/.cargo-checksum.json b/vendor/fs_extra/.cargo-checksum.json new file mode 100644 index 000000000..408d7d719 --- /dev/null +++ b/vendor/fs_extra/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"84508fee5e8b314e18c1fab6d601975bff0b0897b9dbfe1fbf1451efe71a4449","LICENSE":"251ea8ccb1205ce5fa847d6e264d6b6753af62de2cecf2fd9abc0eb02c7c83fc","README.md":"6c72565b5c7e12dcdb4dbaca0034fd5c9721f38bf5952fd96c3947571df26db0","src/dir.rs":"888a2defde401d8fb1da5aa18b58efe210a0fdd9e74bdfa6867c3aa188de0b40","src/error.rs":"7306cb0e85081d7ef4b2d59cf5f068df7585c2d0ce3b5219c7c9448c20801a61","src/file.rs":"e6eefb1b91503b834571f8d27badbca8dac50c50f23d43b03277a52ed2c3edbb","src/lib.rs":"cb4ae7a8080a6de2cf99aae2338486cf777bb300f7d2082d98238b4eb746648c","tests/dir.rs":"20bda4edbaa23397e83361586e5742360fcbbec8f5bf46c9c208ee7b05a13db7","tests/file.rs":"06829b2db83e2805c87b83862c75cb1016ce7d12e5d8236eefbe39ffa16fa553","tests/lib.rs":"567eb582e8e1524b3f6c79cd8683fdd7b11cbd1ba5461b319cf2ffec211eb789"},"package":"42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"} \ No newline at end of file diff --git a/vendor/fs_extra/Cargo.toml b/vendor/fs_extra/Cargo.toml new file mode 100644 index 000000000..3f119234a --- /dev/null +++ b/vendor/fs_extra/Cargo.toml @@ -0,0 +1,26 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "fs_extra" +version = "1.3.0" +authors = ["Denis Kurilenko "] +include = ["**/*.rs", "Cargo.toml", "LICENSE", "README.md", "CHANGELOG.md"] +description = "Expanding std::fs and std::io. Recursively copy folders with information about process and much more." +homepage = "https://github.com/webdesus/fs_extra" +documentation = "https://docs.rs/fs_extra" +keywords = ["filesystem", "recursion", "copy", "dir", "file"] +license = "MIT" +repository = "https://github.com/webdesus/fs_extra" + +[dependencies] diff --git a/vendor/fs_extra/LICENSE b/vendor/fs_extra/LICENSE new file mode 100644 index 000000000..2f97c3d7d --- /dev/null +++ b/vendor/fs_extra/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 Denis Kurilenko + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/fs_extra/README.md b/vendor/fs_extra/README.md new file mode 100644 index 000000000..13aee1ea7 --- /dev/null +++ b/vendor/fs_extra/README.md @@ -0,0 +1,134 @@ +# fs_extra + +A Rust library that provides additional functionality not present in [`std::fs`](https://doc.rust-lang.org/std/fs/index.html). + +[![Build Status](https://travis-ci.org/webdesus/fs_extra.svg)](https://travis-ci.org/webdesus/fs_extra) +[![Crates.io Status](https://img.shields.io/crates/v/fs_extra.svg)](https://crates.io/crates/fs_extra) +[![Docs](https://docs.rs/fs_extra/badge.svg)](https://docs.rs/fs_extra) + +[Documentation](https://docs.rs/fs_extra) + +[Migrations to 1.x.x version](https://github.com/webdesus/fs_extra/wiki/Migrations-to-1.x.x-version) + + +## Key features: + +* Copy files (optionally with information about the progress). + +* Copy directories recursively (optionally with information about the progress). + +* Move files (optionally with information about the progress). + +* Move directories recursively (optionally with information about the progress). + +* A single method for create and write `String` content in file. + +* A single method for open and read `String` content from file. + +* Get folder size + +* Get collection of directory entries + +## Functions: + +| Function | Description | +| ------------- | ------------- | +| [fs_extra::copy_items](https://docs.rs/fs_extra/*/fs_extra/fn.copy_items.html) | Recursively copies files and directories from one location to another | +| [fs_extra::copy_items_with_progress](https://docs.rs/fs_extra/*/fs_extra/fn.copy_items_with_progress.html) | Recursively copies files and directories from one location to another with information about progress | +| [fs_extra::move_items](https://docs.rs/fs_extra/*/fs_extra/fn.move_items.html) | Recursively moves files and directories from one location to another | +| [fs_extra::move_items_with_progress](https://docs.rs/fs_extra/*/fs_extra/fn.move_items_with_progress.html) | Recursively moves files and directories from one location to another with information about progress | +| [fs_extra::remove_items](https://docs.rs/fs_extra/*/fs_extra/fn.remove_items.html) | Removes files or directories | +| [fs_extra::file::copy](https://docs.rs/fs_extra/*/fs_extra/file/fn.copy.html) | Copies the contents of one file to another | +| [fs_extra::file::copy_with_progress](https://docs.rs/fs_extra/*/fs_extra/file/fn.copy_with_progress.html) | Copies the contents of one file to another with information about progress | +| [fs_extra::file::move_file](https://docs.rs/fs_extra/*/fs_extra/file/fn.move_file.html) | Moves a file from one location to another | +| [fs_extra::file::move_file_with_progress](https://docs.rs/fs_extra/*/fs_extra/file/fn.move_file_with_progress.html) | Moves a file from one location to another with information about progress | +| [fs_extra::file::remove](https://docs.rs/fs_extra/*/fs_extra/file/fn.remove.html) | Removes a file | +| [fs_extra::file::read_to_string](https://docs.rs/fs_extra/*/fs_extra/file/fn.read_to_string.html) | Reads file content into a `String` | +| [fs_extra::file::write_all](https://docs.rs/fs_extra/*/fs_extra/file/fn.write_all.html) | Writes `String` content to a file | +| [fs_extra::dir::create](https://docs.rs/fs_extra/*/fs_extra/dir/fn.create.html) | Creates a new, empty directory at the given path | +| [fs_extra::dir::create_all](https://docs.rs/fs_extra/*/fs_extra/dir/fn.create_all.html) | Recursively creates a directory and all of its parent components if they are missing | +| [fs_extra::dir::copy](https://docs.rs/fs_extra/*/fs_extra/dir/fn.copy.html) | Recursively copies the directory contents from one location to another | +| [fs_extra::dir::copy_with_progress](https://docs.rs/fs_extra/*/fs_extra/dir/fn.copy_with_progress.html) | Recursively copies the directory contents from one location to another with information about progress | +| [fs_extra::dir::move_dir](https://docs.rs/fs_extra/*/fs_extra/dir/fn.move_dir.html) | Moves directory contents from one location to another | +| [fs_extra::dir::move_dir_with_progress](https://docs.rs/fs_extra/*/fs_extra/dir/fn.move_dir_with_progress.html) | Moves directory contents from one location to another with information about progress | +| [fs_extra::dir::remove](https://docs.rs/fs_extra/*/fs_extra/dir/fn.remove.html) | Removes directory | +| [fs_extra::dir::get_size](https://docs.rs/fs_extra/*/fs_extra/dir/fn.get_size.html) | Returns the size of the file or directory | +| [fs_extra::dir::get_dir_content](https://docs.rs/fs_extra/*/fs_extra/dir/fn.get_dir_content.html) | Gets details such as the size and child items of a directory | +| [fs_extra::dir::get_dir_content2](https://docs.rs/fs_extra/*/fs_extra/dir/fn.get_dir_content2.html) | Gets details such as the size and child items of a directory using specified settings | +| [fs_extra::dir::get_details_entry](https://docs.rs/fs_extra/*/fs_extra/dir/fn.get_details_entry.html) | Gets attributes of a directory entry | +| [fs_extra::dir::ls](https://docs.rs/fs_extra/*/fs_extra/dir/fn.ls.html) | Gets attributes of directory entries in a directory | + +## Usage + +Add this to your `Cargo.toml`: +```toml +[dependencies] +fs_extra = "1.3.0" +``` +## Examples + +The following example shows how to copy a directory recursively and display progress. First a source directory `./temp/dir` containing file `test1.txt` and a subdirectory `sub` is createad with `sub` itself having a file `test2.txt`. `./temp/dir` and all contents are then copied out to `./out/dir`. + +```rust +use std::path::Path; +use std::{thread, time}; +use std::sync::mpsc::{self, TryRecvError}; + +extern crate fs_extra; +use fs_extra::dir::*; +use fs_extra::error::*; + +fn example_copy() -> Result<()> { + + let path_from = Path::new("./temp"); + let path_to = path_from.join("out"); + let test_folder = path_from.join("test_folder"); + let dir = test_folder.join("dir"); + let sub = dir.join("sub"); + let file1 = dir.join("file1.txt"); + let file2 = sub.join("file2.txt"); + + create_all(&sub, true)?; + create_all(&path_to, true)?; + fs_extra::file::write_all(&file1, "content1")?; + fs_extra::file::write_all(&file2, "content2")?; + + assert!(dir.exists()); + assert!(sub.exists()); + assert!(file1.exists()); + assert!(file2.exists()); + + + let mut options = CopyOptions::new(); + options.buffer_size = 1; + let (tx, rx) = mpsc::channel(); + thread::spawn(move || { + let handler = |process_info: TransitProcess| { + tx.send(process_info).unwrap(); + thread::sleep(time::Duration::from_millis(500)); + fs_extra::dir::TransitProcessResult::ContinueOrAbort + }; + copy_with_progress(&test_folder, &path_to, &options, handler).unwrap(); + }); + + loop { + match rx.try_recv() { + Ok(process_info) => { + println!("{} of {} bytes", + process_info.copied_bytes, + process_info.total_bytes); + } + Err(TryRecvError::Disconnected) => { + println!("finished"); + break; + } + Err(TryRecvError::Empty) => {} + } + } + Ok(()) + +} +fn main() { + example_copy(); +} +``` diff --git a/vendor/fs_extra/src/dir.rs b/vendor/fs_extra/src/dir.rs new file mode 100644 index 000000000..a5d111249 --- /dev/null +++ b/vendor/fs_extra/src/dir.rs @@ -0,0 +1,1398 @@ +use crate::error::*; +use std::collections::{HashMap, HashSet}; +use std::fs::{create_dir, create_dir_all, read_dir, remove_dir_all, Metadata}; +use std::path::{Path, PathBuf}; +use std::time::SystemTime; + +/// Options and flags which can be used to configure how a file will be copied or moved. +#[derive(Clone)] +pub struct CopyOptions { + /// Overwrite existing files if true (default: false). + pub overwrite: bool, + /// Skip existing files if true (default: false). + pub skip_exist: bool, + /// Buffer size that specifies the amount of bytes to be moved or copied before the progress handler is called. This only affects functions with progress handlers. (default: 64000) + pub buffer_size: usize, + /// Recursively copy a directory with a new name or place it inside the destination (default: false, same behaviors as cp -r on Unix) + pub copy_inside: bool, + /// Copy only contents without a creating a new folder in the destination folder (default: false). + pub content_only: bool, + /// Sets levels reading. Set 0 for read all directory folder (default: 0). + /// + /// Warning: Work only for copy operations! + pub depth: u64, +} + +impl CopyOptions { + /// Initialize struct CopyOptions with default value. + /// + /// ```rust,ignore + /// overwrite: false + /// + /// skip_exist: false + /// + /// buffer_size: 64000 // 64kb + /// + /// copy_inside: false + /// ``` + pub fn new() -> CopyOptions { + CopyOptions { + overwrite: false, + skip_exist: false, + buffer_size: 64000, // 64kb + copy_inside: false, + content_only: false, + depth: 0, + } + } + + /// Overwrite existing files if true. + pub fn overwrite(mut self, overwrite: bool) -> Self { + self.overwrite = overwrite; + self + } + + /// Skip existing files if true. + pub fn skip_exist(mut self, skip_exist: bool) -> Self { + self.skip_exist = skip_exist; + self + } + + /// Buffer size that specifies the amount of bytes to be moved or copied before the progress handler is called. This only affects functions with progress handlers. + pub fn buffer_size(mut self, buffer_size: usize) -> Self { + self.buffer_size = buffer_size; + self + } + + /// Recursively copy a directory with a new name or place it inside the destination (default: false, same behaviors as cp -r on Unix) + pub fn copy_inside(mut self, copy_inside: bool) -> Self { + self.copy_inside = copy_inside; + self + } + + /// Copy only contents without a creating a new folder in the destination folder. + pub fn content_only(mut self, content_only: bool) -> Self { + self.content_only = content_only; + self + } + + /// Sets levels reading. Set 0 for read all directory folder + pub fn depth(mut self, depth: u64) -> Self { + self.depth = depth; + self + } +} + +impl Default for CopyOptions { + fn default() -> Self { + CopyOptions::new() + } +} + +// Options and flags which can be used to configure how to read a directory. +#[derive(Clone, Default)] +pub struct DirOptions { + /// Sets levels reading. Set value 0 for read all directory folder. By default 0. + pub depth: u64, +} + +impl DirOptions { + /// Initialize struct DirOptions with default value. + pub fn new() -> DirOptions { + Default::default() + } +} + +/// A structure which include information about directory +pub struct DirContent { + /// Directory size in bytes. + pub dir_size: u64, + /// List all files directory and sub directories. + pub files: Vec, + /// List all folders and sub folders directory. + pub directories: Vec, +} + +/// A structure which include information about the current status of the copy or move directory. +pub struct TransitProcess { + /// Copied bytes on this time for folder + pub copied_bytes: u64, + /// All the bytes which should to copy or move (dir size). + pub total_bytes: u64, + /// Copied bytes on this time for file. + pub file_bytes_copied: u64, + /// Size current copied file. + pub file_total_bytes: u64, + /// Name current copied file. + pub file_name: String, + /// Transit state + pub state: TransitState, +} + +/// +#[derive(Hash, Eq, PartialEq, Clone)] +pub enum TransitState { + /// Standard state. + Normal, + /// Pause state when destination path exists. + Exists, + /// Pause state when current process does not have the permission to access from or to + /// path. + NoAccess, +} + +/// Available returns codes for user decide +pub enum TransitProcessResult { + /// Rewrite exist file or directory. + Overwrite, + /// Rewrite for all exist files or directories. + OverwriteAll, + /// Skip current problem file or directory. + Skip, + /// Skip for all problems file or directory. + SkipAll, + /// Retry current operation. + Retry, + /// Abort current operation. + Abort, + /// Continue execute process if process not have error and abort if process content error. + ContinueOrAbort, +} + +impl Clone for TransitProcess { + fn clone(&self) -> TransitProcess { + TransitProcess { + copied_bytes: self.copied_bytes, + total_bytes: self.total_bytes, + file_bytes_copied: self.file_bytes_copied, + file_total_bytes: self.file_total_bytes, + file_name: self.file_name.clone(), + state: self.state.clone(), + } + } +} + +/// Available attributes for get information about directory entry. +#[derive(Hash, Eq, PartialEq, Clone)] +pub enum DirEntryAttr { + /// Folder name or file name without extension. + Name, + /// File extension. + Ext, + /// Folder name or file name with extension. + FullName, + /// Path to file or directory. + Path, + /// Dos path to file or directory. + DosPath, + /// File size in bytes. + FileSize, + /// Size file or directory in bytes. + /// + /// `Attention!`: This operation very expensive and sometimes required additional rights. + Size, + /// Return whether entry is directory or not. + IsDir, + /// Return whether entry is file or not. + IsFile, + /// Last modification time for directory entry. + Modified, + /// Last access time for directory entry. + Accessed, + /// Created time for directory entry. + /// + /// `Attention!`: Not supported UNIX platform. + Created, + /// Return or not return base information target folder. + BaseInfo, +} + +/// Available types for directory entry. +pub enum DirEntryValue { + /// String type + String(String), + /// Boolean type + Boolean(bool), + /// SystemTime type + SystemTime(SystemTime), + /// u64 type + U64(u64), +} + +/// Result returned by the `ls` function. +pub struct LsResult { + /// Base folder target path + pub base: HashMap, + /// Collection directory entry with information. + pub items: Vec>, +} + +/// Returned information about directory entry with information which you choose in config. +/// +/// This function takes to arguments: +/// +/// * `path` - Path to directory. +/// +/// * `config` - Set attributes which you want see inside return data. +/// +/// # Errors +/// +/// This function will return an error in the following situations, but is not limited to just +/// these cases: +/// +/// * This `path` does not exist. +/// * Invalid `path`. +/// * The current process does not have the permission to access `path`. +/// +/// #Examples +/// +/// ```rust,ignore +/// extern crate fs_extra; +/// use fs_extra::dir::{get_details_entry, DirEntryAttr}; +/// use std::collections::{HashMap, HashSet}; +/// +/// let mut config = HashSet::new(); +/// config.insert(DirEntryAttr::Name); +/// config.insert(DirEntryAttr::Size); +/// +/// let entry_info = get_details_entry("test", &config); +/// assert_eq!(2, entry_info.len()); +/// ``` +pub fn get_details_entry

( + path: P, + config: &HashSet, +) -> Result> +where + P: AsRef, +{ + let path = path.as_ref(); + let metadata = path.metadata()?; + get_details_entry_with_meta(path, config, metadata) +} + +fn get_details_entry_with_meta

( + path: P, + config: &HashSet, + metadata: Metadata, +) -> Result> +where + P: AsRef, +{ + let path = path.as_ref(); + let mut item = HashMap::new(); + if config.contains(&DirEntryAttr::Name) { + if metadata.is_dir() { + if let Some(file_name) = path.file_name() { + item.insert( + DirEntryAttr::Name, + DirEntryValue::String(file_name.to_os_string().into_string()?), + ); + } else { + item.insert(DirEntryAttr::Name, DirEntryValue::String(String::new())); + } + } else if let Some(file_stem) = path.file_stem() { + item.insert( + DirEntryAttr::Name, + DirEntryValue::String(file_stem.to_os_string().into_string()?), + ); + } else { + item.insert(DirEntryAttr::Name, DirEntryValue::String(String::new())); + } + } + if config.contains(&DirEntryAttr::Ext) { + if let Some(value) = path.extension() { + item.insert( + DirEntryAttr::Ext, + DirEntryValue::String(value.to_os_string().into_string()?), + ); + } else { + item.insert(DirEntryAttr::Ext, DirEntryValue::String(String::from(""))); + } + } + if config.contains(&DirEntryAttr::FullName) { + if let Some(file_name) = path.file_name() { + item.insert( + DirEntryAttr::FullName, + DirEntryValue::String(file_name.to_os_string().into_string()?), + ); + } else { + item.insert(DirEntryAttr::FullName, DirEntryValue::String(String::new())); + } + } + if config.contains(&DirEntryAttr::Path) { + let mut result_path: PathBuf; + match path.canonicalize() { + Ok(new_path) => { + result_path = new_path; + } + Err(_) => { + if let Some(parent_path) = path.parent() { + if let Some(name) = path.file_name() { + result_path = parent_path.canonicalize()?; + result_path.push(name); + } else { + err!("Error get part name path", ErrorKind::Other); + } + } else { + err!("Error get parent path", ErrorKind::Other); + } + } + } + let mut path = result_path.as_os_str().to_os_string().into_string()?; + if path.find("\\\\?\\") == Some(0) { + path = path[4..].to_string(); + } + item.insert(DirEntryAttr::Path, DirEntryValue::String(path)); + } + if config.contains(&DirEntryAttr::DosPath) { + let mut result_path: PathBuf; + match path.canonicalize() { + Ok(new_path) => { + result_path = new_path; + } + Err(_) => { + if let Some(parent_path) = path.parent() { + if let Some(name) = path.file_name() { + result_path = parent_path.canonicalize()?; + result_path.push(name); + } else { + err!("Error get part name path", ErrorKind::Other); + } + } else { + err!("Error get parent path", ErrorKind::Other); + } + } + } + let path = result_path.as_os_str().to_os_string().into_string()?; + item.insert(DirEntryAttr::DosPath, DirEntryValue::String(path)); + } + if config.contains(&DirEntryAttr::Size) { + item.insert(DirEntryAttr::Size, DirEntryValue::U64(get_size(&path)?)); + } + if config.contains(&DirEntryAttr::FileSize) { + item.insert(DirEntryAttr::FileSize, DirEntryValue::U64(metadata.len())); + } + if config.contains(&DirEntryAttr::IsDir) { + item.insert( + DirEntryAttr::IsDir, + DirEntryValue::Boolean(metadata.is_dir()), + ); + } + if config.contains(&DirEntryAttr::IsFile) { + item.insert( + DirEntryAttr::IsFile, + DirEntryValue::Boolean(metadata.is_file()), + ); + } + if config.contains(&DirEntryAttr::Modified) { + item.insert( + DirEntryAttr::Modified, + DirEntryValue::SystemTime(metadata.modified()?), + ); + } + if config.contains(&DirEntryAttr::Accessed) { + item.insert( + DirEntryAttr::Accessed, + DirEntryValue::SystemTime(metadata.accessed()?), + ); + } + if config.contains(&DirEntryAttr::Created) { + item.insert( + DirEntryAttr::Created, + DirEntryValue::SystemTime(metadata.created()?), + ); + } + Ok(item) +} + +/// Returns a collection of directory entries with attributes specifying the information that should be returned. +/// +/// This function takes to arguments: +/// +/// * `path` - Path to directory. +/// +/// * `config` - Set attributes which you want see in return data. +/// +/// # Errors +/// +/// This function will return an error in the following situations, but is not limited to just +/// these cases: +/// +/// * This `path` directory does not exist. +/// * Invalid `path`. +/// * The current process does not have the permission to access `path`. +/// +/// #Examples +/// +/// ```rust,ignore +/// extern crate fs_extra; +/// use fs_extra::dir::{ls, DirEntryAttr, LsResult}; +/// use std::collections::HashSet; +/// +/// let mut config = HashSet::new(); +/// config.insert(DirEntryAttr::Name); +/// config.insert(DirEntryAttr::Size); +/// config.insert(DirEntryAttr::BaseInfo); +/// +/// let result = ls("test", &config); +/// assert_eq!(2, ls_result.items.len()); +/// assert_eq!(2, ls_result.base.len()); +/// ``` +pub fn ls

(path: P, config: &HashSet) -> Result +where + P: AsRef, +{ + let mut items = Vec::new(); + let path = path.as_ref(); + if !path.is_dir() { + err!("Path does not directory", ErrorKind::InvalidFolder); + } + for entry in read_dir(&path)? { + let entry = entry?; + let path = entry.path(); + let metadata = entry.metadata()?; + let item = get_details_entry_with_meta(path, &config, metadata)?; + items.push(item); + } + let mut base = HashMap::new(); + if config.contains(&DirEntryAttr::BaseInfo) { + base = get_details_entry(&path, &config)?; + } + Ok(LsResult { items, base }) +} + +/// Creates a new, empty directory at the provided path. +/// +/// This function takes to arguments: +/// +/// * `path` - Path to new directory. +/// +/// * `erase` - If set true and folder exist, then folder will be erased. +/// +/// #Errors +/// +/// This function will return an error in the following situations, +/// but is not limited to just these cases: +/// +/// * User lacks permissions to create directory at `path`. +/// +/// * `path` already exists if `erase` set false. +/// +/// #Examples +/// +/// ```rust,ignore +/// extern crate fs_extra; +/// use fs_extra::dir::create; +/// +/// create("dir", false); // create directory +/// ``` +pub fn create

(path: P, erase: bool) -> Result<()> +where + P: AsRef, +{ + if erase && path.as_ref().exists() { + remove(&path)?; + } + Ok(create_dir(&path)?) +} + +/// Recursively create a directory and all of its parent components if they are missing. +/// +/// This function takes to arguments: +/// +/// * `path` - Path to new directory. +/// +/// * `erase` - If set true and folder exist, then folder will be erased. +/// +///#Errors +/// +/// This function will return an error in the following situations, +/// but is not limited to just these cases: +/// +/// * User lacks permissions to create directory at `path`. +/// +/// * `path` already exists if `erase` set false. +/// +/// #Examples +/// +/// ```rust,ignore +/// extern crate fs_extra; +/// use fs_extra::dir::create_all; +/// +/// create_all("/some/dir", false); // create directory some and dir +pub fn create_all

(path: P, erase: bool) -> Result<()> +where + P: AsRef, +{ + if erase && path.as_ref().exists() { + remove(&path)?; + } + Ok(create_dir_all(&path)?) +} + +/// Copies the directory contents from one place to another using recursive method. +/// This function will also copy the permission bits of the original files to +/// destination files (not for directories). +/// +/// # Errors +/// +/// This function will return an error in the following situations, but is not limited to just +/// these cases: +/// +/// * This `from` path is not a directory. +/// * This `from` directory does not exist. +/// * Invalid folder name for `from` or `to`. +/// * The current process does not have the permission to access `from` or write `to`. +/// +/// # Example +/// ```rust,ignore +/// extern crate fs_extra; +/// use fs_extra::dir::copy; +/// +/// let options = CopyOptions::new(); //Initialize default values for CopyOptions +/// // options.mirror_copy = true; // To mirror copy the whole structure of the source directory +/// +/// +/// // copy source/dir1 to target/dir1 +/// copy("source/dir1", "target/dir1", &options)?; +/// +/// ``` +pub fn copy(from: P, to: Q, options: &CopyOptions) -> Result +where + P: AsRef, + Q: AsRef, +{ + let from = from.as_ref(); + + if !from.exists() { + if let Some(msg) = from.to_str() { + let msg = format!("Path \"{}\" does not exist or you don't have access!", msg); + err!(&msg, ErrorKind::NotFound); + } + err!( + "Path does not exist Or you don't have access!", + ErrorKind::NotFound + ); + } + if !from.is_dir() { + if let Some(msg) = from.to_str() { + let msg = format!("Path \"{}\" is not a directory!", msg); + err!(&msg, ErrorKind::InvalidFolder); + } + err!("Path is not a directory!", ErrorKind::InvalidFolder); + } + let dir_name; + if let Some(val) = from.components().last() { + dir_name = val.as_os_str(); + } else { + err!("Invalid folder from", ErrorKind::InvalidFolder); + } + let mut to: PathBuf = to.as_ref().to_path_buf(); + if (to.exists() || !options.copy_inside) && !options.content_only { + to.push(dir_name); + } + + let mut read_options = DirOptions::new(); + if options.depth > 0 { + read_options.depth = options.depth; + } + + let dir_content = get_dir_content2(from, &read_options)?; + for directory in dir_content.directories { + let tmp_to = Path::new(&directory).strip_prefix(from)?; + let dir = to.join(&tmp_to); + if !dir.exists() { + if options.copy_inside { + create_all(dir, false)?; + } else { + create(dir, false)?; + } + } + } + let mut result: u64 = 0; + for file in dir_content.files { + let to = to.to_path_buf(); + let tp = Path::new(&file).strip_prefix(from)?; + let path = to.join(&tp); + + let file_options = super::file::CopyOptions { + overwrite: options.overwrite, + skip_exist: options.skip_exist, + buffer_size: options.buffer_size, + }; + let mut result_copy: Result; + let mut work = true; + + while work { + result_copy = super::file::copy(&file, &path, &file_options); + match result_copy { + Ok(val) => { + result += val; + work = false; + } + Err(err) => { + let err_msg = err.to_string(); + err!(err_msg.as_str(), err.kind) + } + } + } + } + Ok(result) +} + +/// Return DirContent which contains information about directory: +/// +/// * Size of the directory in bytes. +/// * List of source paths of files in the directory (files inside subdirectories included too). +/// * List of source paths of all directories and subdirectories. +/// +/// # Errors +/// +/// This function will return an error in the following situations, but is not limited to just +/// these cases: +/// +/// * This `path` directory does not exist. +/// * Invalid `path`. +/// * The current process does not have the permission to access `path`. +/// +/// # Examples +/// ```rust,ignore +/// extern crate fs_extra; +/// use fs_extra::dir::get_dir_content; +/// +/// let dir_content = get_dir_content("dir")?; +/// for directory in dir_content.directories { +/// println!("{}", directory); // print directory path +/// } +/// ``` +/// +pub fn get_dir_content

(path: P) -> Result +where + P: AsRef, +{ + let options = DirOptions::new(); + get_dir_content2(path, &options) +} + +/// Return DirContent which contains information about directory: +/// +/// * Size directory. +/// * List all files source directory(files subdirectories included too). +/// * List all directory and subdirectories source path. +/// +/// # Errors +/// +/// This function will return an error in the following situations, but is not limited to just +/// these cases: +/// +/// * This `path` directory does not exist. +/// * Invalid `path`. +/// * The current process does not have the permission to access `path`. +/// +/// # Examples +/// ```rust,ignore +/// extern crate fs_extra; +/// use fs_extra::dir::{DirOptions, get_dir_content2}; +/// +/// let mut options = DirOptions::new(); +/// options.depth = 3; // Get 3 levels of folder. +/// let dir_content = get_dir_content2("dir", &options)?; +/// for directory in dir_content.directories { +/// println!("{}", directory); // print directory path +/// } +/// ``` +/// +pub fn get_dir_content2

(path: P, options: &DirOptions) -> Result +where + P: AsRef, +{ + let mut depth = 0; + if options.depth != 0 { + depth = options.depth + 1; + } + _get_dir_content(path, depth) +} + +fn _get_dir_content

(path: P, mut depth: u64) -> Result +where + P: AsRef, +{ + let mut directories = Vec::new(); + let mut files = Vec::new(); + let mut dir_size; + let item = path.as_ref().to_str(); + if item.is_none() { + err!("Invalid path", ErrorKind::InvalidPath); + } + let item = item.unwrap().to_string(); + + if path.as_ref().is_dir() { + dir_size = path.as_ref().metadata()?.len(); + directories.push(item); + if depth == 0 || depth > 1 { + if depth > 1 { + depth -= 1; + } + for entry in read_dir(&path)? { + let _path = entry?.path(); + + match _get_dir_content(_path, depth) { + Ok(items) => { + let mut _files = items.files; + let mut _directories = items.directories; + dir_size += items.dir_size; + files.append(&mut _files); + directories.append(&mut _directories); + } + Err(err) => return Err(err), + } + } + } + } else { + dir_size = path.as_ref().metadata()?.len(); + files.push(item); + } + Ok(DirContent { + dir_size, + files, + directories, + }) +} + +/// Returns the size of the file or directory in bytes.(!important: folders size not count) +/// +/// If used on a directory, this function will recursively iterate over every file and every +/// directory inside the directory. This can be very time consuming if used on large directories. +/// +/// Does not follow symlinks. +/// +/// # Errors +/// +/// This function will return an error in the following situations, but is not limited to just +/// these cases: +/// +/// * This `path` directory does not exist. +/// * Invalid `path`. +/// * The current process does not have the permission to access `path`. +/// +/// # Examples +/// ```rust,ignore +/// extern crate fs_extra; +/// use fs_extra::dir::get_size; +/// +/// let folder_size = get_size("dir")?; +/// println!("{}", folder_size); // print directory size in bytes +/// ``` +pub fn get_size

(path: P) -> Result +where + P: AsRef, +{ + // Using `fs::symlink_metadata` since we don't want to follow symlinks, + // as we're calculating the exact size of the requested path itself. + let path_metadata = path.as_ref().symlink_metadata()?; + + let mut size_in_bytes = 0; + + if path_metadata.is_dir() { + for entry in read_dir(&path)? { + let entry = entry?; + // `DirEntry::metadata` does not follow symlinks (unlike `fs::metadata`), so in the + // case of symlinks, this is the size of the symlink itself, not its target. + let entry_metadata = entry.metadata()?; + + if entry_metadata.is_dir() { + // The size of the directory entry itself will be counted inside the `get_size()` call, + // so we intentionally don't also add `entry_metadata.len()` to the total here. + size_in_bytes += get_size(entry.path())?; + } else { + size_in_bytes += entry_metadata.len(); + } + } + } else { + size_in_bytes = path_metadata.len(); + } + + Ok(size_in_bytes) +} + +/// Copies the directory contents from one place to another using recursive method, +/// with information about progress. This function will also copy the +/// permission bits of the original files to destination files (not for directories). +/// +/// # Errors +/// +/// This function will return an error in the following situations, but is not limited to just +/// these cases: +/// +/// * This `from` path is not a directory. +/// * This `from` directory does not exist. +/// * Invalid folder name for `from` or `to`. +/// * The current process does not have the permission to access `from` or write `to`. +/// +/// # Example +/// ```rust,ignore +/// extern crate fs_extra; +/// use fs_extra::dir::copy; +/// +/// let options = CopyOptions::new(); //Initialize default values for CopyOptions +/// let handle = |process_info: TransitProcess| { +/// println!("{}", process_info.total_bytes); +/// fs_extra::dir::TransitProcessResult::ContinueOrAbort +/// } +/// // copy source/dir1 to target/dir1 +/// copy_with_progress("source/dir1", "target/dir1", &options, handle)?; +/// +/// ``` +pub fn copy_with_progress( + from: P, + to: Q, + options: &CopyOptions, + mut progress_handler: F, +) -> Result +where + P: AsRef, + Q: AsRef, + F: FnMut(TransitProcess) -> TransitProcessResult, +{ + let from = from.as_ref(); + + if !from.exists() { + if let Some(msg) = from.to_str() { + let msg = format!("Path \"{}\" does not exist or you don't have access!", msg); + err!(&msg, ErrorKind::NotFound); + } + err!( + "Path does not exist or you don't have access!", + ErrorKind::NotFound + ); + } + + let mut to: PathBuf = to.as_ref().to_path_buf(); + if !from.is_dir() { + if let Some(msg) = from.to_str() { + let msg = format!("Path \"{}\" is not a directory!", msg); + err!(&msg, ErrorKind::InvalidFolder); + } + err!("Path is not a directory!", ErrorKind::InvalidFolder); + } + + let dir_name; + if let Some(val) = from.components().last() { + dir_name = val.as_os_str(); + } else { + err!("Invalid folder from", ErrorKind::InvalidFolder); + } + if (to.exists() || !options.copy_inside) && !options.content_only { + to.push(dir_name); + } + + let mut read_options = DirOptions::new(); + if options.depth > 0 { + read_options.depth = options.depth; + } + + let dir_content = get_dir_content2(from, &read_options)?; + for directory in dir_content.directories { + let tmp_to = Path::new(&directory).strip_prefix(from)?; + let dir = to.join(&tmp_to); + if !dir.exists() { + if options.copy_inside { + create_all(dir, false)?; + } else { + create(dir, false)?; + } + } + } + + let mut result: u64 = 0; + let mut info_process = TransitProcess { + copied_bytes: 0, + total_bytes: dir_content.dir_size, + file_bytes_copied: 0, + file_total_bytes: 0, + file_name: String::new(), + state: TransitState::Normal, + }; + + let mut options = options.clone(); + for file in dir_content.files { + let mut to = to.to_path_buf(); + let tp = Path::new(&file).strip_prefix(from)?; + let path = to.join(&tp); + + let file_name = path.file_name(); + if file_name.is_none() { + err!("No file name"); + } + let file_name = file_name.unwrap(); + to.push(file_name); + + let mut file_options = super::file::CopyOptions { + overwrite: options.overwrite, + skip_exist: options.skip_exist, + buffer_size: options.buffer_size, + }; + + if let Some(file_name) = file_name.to_str() { + info_process.file_name = file_name.to_string(); + } else { + err!("Invalid file name", ErrorKind::InvalidFileName); + } + + info_process.file_bytes_copied = 0; + info_process.file_total_bytes = Path::new(&file).metadata()?.len(); + + let mut result_copy: Result; + let mut work = true; + let copied_bytes = result; + while work { + { + let _progress_handler = |info: super::file::TransitProcess| { + info_process.copied_bytes = copied_bytes + info.copied_bytes; + info_process.file_bytes_copied = info.copied_bytes; + progress_handler(info_process.clone()); + }; + + result_copy = + super::file::copy_with_progress(&file, &path, &file_options, _progress_handler); + } + match result_copy { + Ok(val) => { + result += val; + work = false; + } + Err(err) => match err.kind { + ErrorKind::AlreadyExists => { + let mut info_process = info_process.clone(); + info_process.state = TransitState::Exists; + let user_decide = progress_handler(info_process); + match user_decide { + TransitProcessResult::Overwrite => { + file_options.overwrite = true; + } + TransitProcessResult::OverwriteAll => { + file_options.overwrite = true; + options.overwrite = true; + } + TransitProcessResult::Skip => { + file_options.skip_exist = true; + } + TransitProcessResult::SkipAll => { + file_options.skip_exist = true; + options.skip_exist = true; + } + TransitProcessResult::Retry => {} + TransitProcessResult::ContinueOrAbort => { + let err_msg = err.to_string(); + err!(err_msg.as_str(), err.kind) + } + TransitProcessResult::Abort => { + let err_msg = err.to_string(); + err!(err_msg.as_str(), err.kind) + } + } + } + ErrorKind::PermissionDenied => { + let mut info_process = info_process.clone(); + info_process.state = TransitState::Exists; + let user_decide = progress_handler(info_process); + match user_decide { + TransitProcessResult::Overwrite => { + err!("Overwrite denied for this situation!", ErrorKind::Other); + } + TransitProcessResult::OverwriteAll => { + err!("Overwrite denied for this situation!", ErrorKind::Other); + } + TransitProcessResult::Skip => { + file_options.skip_exist = true; + } + TransitProcessResult::SkipAll => { + file_options.skip_exist = true; + options.skip_exist = true; + } + TransitProcessResult::Retry => {} + TransitProcessResult::ContinueOrAbort => { + let err_msg = err.to_string(); + err!(err_msg.as_str(), err.kind) + } + TransitProcessResult::Abort => { + let err_msg = err.to_string(); + err!(err_msg.as_str(), err.kind) + } + } + } + _ => { + let err_msg = err.to_string(); + err!(err_msg.as_str(), err.kind) + } + }, + } + } + } + + Ok(result) +} + +/// Moves the directory contents from one place to another. +/// This function will also copy the permission bits of the original files to +/// destination files (not for directories). +/// +/// # Errors +/// +/// This function will return an error in the following situations, but is not limited to just +/// these cases: +/// +/// * This `from` path is not a directory. +/// * This `from` directory does not exist. +/// * Invalid folder name for `from` or `to`. +/// * The current process does not have the permission to access `from` or write `to`. +/// +/// # Example +/// ```rust,ignore +/// extern crate fs_extra; +/// use fs_extra::dir::move_dir; +/// +/// let options = CopyOptions::new(); //Initialize default values for CopyOptions +/// +/// // move source/dir1 to target/dir1 +/// move_dir("source/dir1", "target/dir1", &options)?; +/// +/// ``` +pub fn move_dir(from: P, to: Q, options: &CopyOptions) -> Result +where + P: AsRef, + Q: AsRef, +{ + let mut is_remove = true; + if options.skip_exist && to.as_ref().exists() && !options.overwrite { + is_remove = false; + } + let from = from.as_ref(); + + if !from.exists() { + if let Some(msg) = from.to_str() { + let msg = format!("Path \"{}\" does not exist", msg); + err!(&msg, ErrorKind::NotFound); + } + err!( + "Path does not exist or you don't have access!", + ErrorKind::NotFound + ); + } + + let mut to: PathBuf = to.as_ref().to_path_buf(); + if !from.is_dir() { + if let Some(msg) = from.to_str() { + let msg = format!( + "Path \"{}\" is not a directory or you don't have access!", + msg + ); + err!(&msg, ErrorKind::InvalidFolder); + } + err!( + "Path is not a directory or you don't have access!", + ErrorKind::InvalidFolder + ); + } + let dir_name; + if let Some(val) = from.components().last() { + dir_name = val.as_os_str(); + } else { + err!("Invalid folder from", ErrorKind::InvalidFolder); + } + + if (to.exists() || !options.copy_inside) && !options.content_only { + to.push(dir_name); + } + let dir_content = get_dir_content(from)?; + for directory in dir_content.directories { + let tmp_to = Path::new(&directory).strip_prefix(from)?; + let dir = to.join(&tmp_to); + if !dir.exists() { + if options.copy_inside { + create_all(dir, false)?; + } else { + create(dir, false)?; + } + } + } + let mut result: u64 = 0; + for file in dir_content.files { + let to = to.to_path_buf(); + let tp = Path::new(&file).strip_prefix(from)?; + let path = to.join(&tp); + + let file_options = super::file::CopyOptions { + overwrite: options.overwrite, + skip_exist: options.skip_exist, + buffer_size: options.buffer_size, + }; + + let mut result_copy: Result; + let mut work = true; + while work { + { + result_copy = super::file::move_file(&file, &path, &file_options); + match result_copy { + Ok(val) => { + result += val; + work = false; + } + Err(err) => { + let err_msg = err.to_string(); + err!(err_msg.as_str(), err.kind) + } + } + } + } + } + if is_remove { + remove(from)?; + } + + Ok(result) +} + +/// Moves the directory contents from one place to another with information about progress. +/// This function will also copy the permission bits of the original files to +/// destination files (not for directories). +/// +/// # Errors +/// +/// This function will return an error in the following situations, but is not limited to just +/// these cases: +/// +/// * This `from` path is not a directory. +/// * This `from` directory does not exist. +/// * Invalid folder name for `from` or `to`. +/// * The current process does not have the permission to access `from` or write `to`. +/// +/// # Example +/// ```rust,ignore +/// extern crate fs_extra; +/// use fs_extra::dir::move_dir_with_progress; +/// +/// let options = CopyOptions::new(); //Initialize default values for CopyOptions +/// let handle = |process_info: TransitProcess| { +/// println!("{}", process_info.total_bytes); +/// fs_extra::dir::TransitProcessResult::ContinueOrAbort +/// } +/// +/// // move source/dir1 to target/dir1 +/// move_dir_with_progress("source/dir1", "target/dir1", &options, handle)?; +/// +/// ``` +pub fn move_dir_with_progress( + from: P, + to: Q, + options: &CopyOptions, + mut progress_handler: F, +) -> Result +where + P: AsRef, + Q: AsRef, + F: FnMut(TransitProcess) -> TransitProcessResult, +{ + let mut is_remove = true; + if options.skip_exist && to.as_ref().exists() && !options.overwrite { + is_remove = false; + } + let from = from.as_ref(); + + if !from.exists() { + if let Some(msg) = from.to_str() { + let msg = format!("Path \"{}\" does not exist or you don't have access!", msg); + err!(&msg, ErrorKind::NotFound); + } + err!( + "Path does not exist or you don't have access!", + ErrorKind::NotFound + ); + } + + let mut to: PathBuf = to.as_ref().to_path_buf(); + if !from.is_dir() { + if let Some(msg) = from.to_str() { + let msg = format!("Path \"{}\" is not a directory!", msg); + err!(&msg, ErrorKind::InvalidFolder); + } + err!("Path is not a directory!", ErrorKind::InvalidFolder); + } + let dir_name; + if let Some(val) = from.components().last() { + dir_name = val.as_os_str(); + } else { + err!("Invalid folder from", ErrorKind::InvalidFolder); + } + if !(options.content_only || options.copy_inside && !to.exists()) { + to.push(dir_name); + } + + let dir_content = get_dir_content(from)?; + for directory in dir_content.directories { + let tmp_to = Path::new(&directory).strip_prefix(from)?; + let dir = to.join(&tmp_to); + if !dir.exists() { + if options.copy_inside { + create_all(dir, false)?; + } else { + create(dir, false)?; + } + } + } + + let mut result: u64 = 0; + let mut info_process = TransitProcess { + copied_bytes: 0, + total_bytes: dir_content.dir_size, + file_bytes_copied: 0, + file_total_bytes: 0, + file_name: String::new(), + state: TransitState::Normal, + }; + + let mut options = options.clone(); + for file in dir_content.files { + let mut to = to.to_path_buf(); + let tp = Path::new(&file).strip_prefix(from)?; + let path = to.join(&tp); + + let file_name = path.file_name(); + if file_name.is_none() { + err!("No file name"); + } + let file_name = file_name.unwrap(); + to.push(file_name); + + let mut file_options = super::file::CopyOptions { + overwrite: options.overwrite, + skip_exist: options.skip_exist, + buffer_size: options.buffer_size, + }; + + if let Some(file_name) = file_name.to_str() { + info_process.file_name = file_name.to_string(); + } else { + err!("Invalid file name", ErrorKind::InvalidFileName); + } + + info_process.file_bytes_copied = 0; + info_process.file_total_bytes = Path::new(&file).metadata()?.len(); + + let mut result_copy: Result; + let mut work = true; + let copied_bytes = result; + while work { + { + let _progress_handler = |info: super::file::TransitProcess| { + info_process.copied_bytes = copied_bytes + info.copied_bytes; + info_process.file_bytes_copied = info.copied_bytes; + progress_handler(info_process.clone()); + }; + + result_copy = super::file::move_file_with_progress( + &file, + &path, + &file_options, + _progress_handler, + ); + } + match result_copy { + Ok(val) => { + result += val; + work = false; + } + Err(err) => match err.kind { + ErrorKind::AlreadyExists => { + let mut info_process = info_process.clone(); + info_process.state = TransitState::Exists; + let user_decide = progress_handler(info_process); + match user_decide { + TransitProcessResult::Overwrite => { + file_options.overwrite = true; + } + TransitProcessResult::OverwriteAll => { + file_options.overwrite = true; + options.overwrite = true; + } + TransitProcessResult::Skip => { + is_remove = false; + file_options.skip_exist = true; + } + TransitProcessResult::SkipAll => { + is_remove = false; + file_options.skip_exist = true; + options.skip_exist = true; + } + TransitProcessResult::Retry => {} + TransitProcessResult::ContinueOrAbort => { + let err_msg = err.to_string(); + err!(err_msg.as_str(), err.kind) + } + TransitProcessResult::Abort => { + let err_msg = err.to_string(); + err!(err_msg.as_str(), err.kind) + } + } + } + ErrorKind::PermissionDenied => { + let mut info_process = info_process.clone(); + info_process.state = TransitState::Exists; + let user_decide = progress_handler(info_process); + match user_decide { + TransitProcessResult::Overwrite => { + err!("Overwrite denied for this situation!", ErrorKind::Other); + } + TransitProcessResult::OverwriteAll => { + err!("Overwrite denied for this situation!", ErrorKind::Other); + } + TransitProcessResult::Skip => { + is_remove = false; + file_options.skip_exist = true; + } + TransitProcessResult::SkipAll => { + file_options.skip_exist = true; + options.skip_exist = true; + } + TransitProcessResult::Retry => {} + TransitProcessResult::ContinueOrAbort => { + let err_msg = err.to_string(); + err!(err_msg.as_str(), err.kind) + } + TransitProcessResult::Abort => { + let err_msg = err.to_string(); + err!(err_msg.as_str(), err.kind) + } + } + } + _ => { + let err_msg = err.to_string(); + err!(err_msg.as_str(), err.kind) + } + }, + } + } + } + if is_remove { + remove(from)?; + } + + Ok(result) +} + +/// Removes directory. +/// +/// # Example +/// ```rust,ignore +/// extern crate fs_extra; +/// use fs_extra::dir::remove; +/// +/// remove("source/dir1"); // remove dir1 +/// ``` +pub fn remove>(path: P) -> Result<()> { + if path.as_ref().exists() { + Ok(remove_dir_all(path)?) + } else { + Ok(()) + } +} diff --git a/vendor/fs_extra/src/error.rs b/vendor/fs_extra/src/error.rs new file mode 100644 index 000000000..f26613e90 --- /dev/null +++ b/vendor/fs_extra/src/error.rs @@ -0,0 +1,158 @@ +use std::error::Error as StdError; +use std::ffi::OsString; +use std::fmt; +use std::io::Error as IoError; +use std::io::ErrorKind as IoErrorKind; +use std::path::StripPrefixError; + +/// A list specifying general categories of fs_extra error. +#[derive(Debug)] +pub enum ErrorKind { + /// An entity was not found. + NotFound, + /// The operation lacked the necessary privileges to complete. + PermissionDenied, + /// An entity already exists. + AlreadyExists, + /// This operation was interrupted. + Interrupted, + /// Path does not a directory. + InvalidFolder, + /// Path does not a file. + InvalidFile, + /// Invalid file name. + InvalidFileName, + /// Invalid path. + InvalidPath, + /// Any I/O error. + Io(IoError), + /// Any StripPrefix error. + StripPrefix(StripPrefixError), + /// Any OsString error. + OsString(OsString), + /// Any fs_extra error not part of this list. + Other, +} + +impl ErrorKind { + fn as_str(&self) -> &str { + match *self { + ErrorKind::NotFound => "entity not found", + ErrorKind::PermissionDenied => "permission denied", + ErrorKind::AlreadyExists => "entity already exists", + ErrorKind::Interrupted => "operation interrupted", + ErrorKind::Other => "other os error", + ErrorKind::InvalidFolder => "invalid folder error", + ErrorKind::InvalidFile => "invalid file error", + ErrorKind::InvalidFileName => "invalid file name error", + ErrorKind::InvalidPath => "invalid path error", + ErrorKind::Io(_) => "Io error", + ErrorKind::StripPrefix(_) => "Strip prefix error", + ErrorKind::OsString(_) => "OsString error", + } + } +} + +/// A specialized Result type for fs_extra operations. +/// +/// This typedef is generally used to avoid writing out fs_extra::Error directly +/// and is otherwise a direct mapping to Result. +/// +///#Examples +/// +/// ```rust,ignore +/// extern crate fs_extra; +/// use fs_extra::dir::create; +/// +///fn get_string() -> io::Result<()> { +/// +/// create("test_dir")?; +/// +/// Ok(()) +/// } +/// ``` +pub type Result = ::std::result::Result; + +/// The error type for fs_extra operations with files and folder. +/// +/// Errors mostly originate from the underlying OS, but custom instances of +/// `Error` can be created with crafted error messages and a particular value of +/// [`ErrorKind`]. +/// +/// [`ErrorKind`]: enum.ErrorKind.html +#[derive(Debug)] +pub struct Error { + /// Type error + pub kind: ErrorKind, + message: String, +} + +impl Error { + /// Create a new fs_extra error from a kind of error error as well as an arbitrary error payload. + /// + ///#Examples + /// ```rust,ignore + /// + /// extern crate fs_extra; + /// use fs_extra::error::{Error, ErrorKind}; + /// + /// errors can be created from strings + /// let custom_error = Error::new(ErrorKind::Other, "Other Error!"); + /// // errors can also be created from other errors + /// let custom_error2 = Error::new(ErrorKind::Interrupted, custom_error); + /// + /// ``` + pub fn new(kind: ErrorKind, message: &str) -> Error { + Error { + kind, + message: message.to_string(), + } + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.message) + } +} + +impl StdError for Error { + fn description(&self) -> &str { + self.kind.as_str() + } +} +impl From for Error { + fn from(err: StripPrefixError) -> Error { + Error::new( + ErrorKind::StripPrefix(err), + "StripPrefixError. Look inside for more details", + ) + } +} + +impl From for Error { + fn from(err: OsString) -> Error { + Error::new( + ErrorKind::OsString(err), + "OsString. Look inside for more details", + ) + } +} + +impl From for Error { + fn from(err: IoError) -> Error { + let err_kind: ErrorKind; + match err.kind() { + IoErrorKind::NotFound => err_kind = ErrorKind::NotFound, + IoErrorKind::PermissionDenied => err_kind = ErrorKind::PermissionDenied, + IoErrorKind::AlreadyExists => err_kind = ErrorKind::AlreadyExists, + IoErrorKind::Interrupted => err_kind = ErrorKind::Interrupted, + IoErrorKind::Other => err_kind = ErrorKind::Other, + _ => { + err_kind = ErrorKind::Io(err); + return Error::new(err_kind, "Io error. Look inside err_kind for more details."); + } + } + Error::new(err_kind, &err.to_string()) + } +} diff --git a/vendor/fs_extra/src/file.rs b/vendor/fs_extra/src/file.rs new file mode 100644 index 000000000..2b62576bc --- /dev/null +++ b/vendor/fs_extra/src/file.rs @@ -0,0 +1,413 @@ +use crate::error::{Error, ErrorKind, Result}; +use std; +use std::fs::{remove_file, File}; +use std::io::{Read, Write}; +use std::path::Path; + +// Options and flags which can be used to configure how a file will be copied or moved. +pub struct CopyOptions { + /// Sets the option true for overwrite existing files. + pub overwrite: bool, + /// Sets the option true for skip existing files. + pub skip_exist: bool, + /// Sets buffer size for copy/move work only with receipt information about process work. + pub buffer_size: usize, +} + +impl CopyOptions { + /// Initialize struct CopyOptions with default value. + /// + /// ```rust,ignore + /// + /// overwrite: false + /// + /// skip_exist: false + /// + /// buffer_size: 64000 //64kb + /// ``` + pub fn new() -> CopyOptions { + CopyOptions { + overwrite: false, + skip_exist: false, + buffer_size: 64000, //64kb + } + } + + /// Sets the option true for overwrite existing files. + pub fn overwrite(mut self, overwrite: bool) -> Self { + self.overwrite = overwrite; + self + } + + /// Sets the option true for skip existing files. + pub fn skip_exist(mut self, skip_exist: bool) -> Self { + self.skip_exist = skip_exist; + self + } + + /// Sets buffer size for copy/move work only with receipt information about process work. + pub fn buffer_size(mut self, buffer_size: usize) -> Self { + self.buffer_size = buffer_size; + self + } +} + +impl Default for CopyOptions { + fn default() -> Self { + CopyOptions::new() + } +} + +/// A structure which stores information about the current status of a file that's copied or moved. . +pub struct TransitProcess { + /// Copied bytes on this time. + pub copied_bytes: u64, + /// All the bytes which should to copy or move. + pub total_bytes: u64, +} + +/// Copies the contents of one file to another. This function will also copy the permission +/// bits of the original file to the destination file. +/// +/// # Errors +/// +/// This function will return an error in the following situations, but is not limited to just +/// these cases: +/// +/// * This `from` path is not a file. +/// * This `from` file does not exist. +/// * The current process does not have the permission to access `from` or write `to`. +/// +/// # Example +/// +/// ```rust,ignore +/// extern crate fs_extra; +/// use fs_extra::file::copy; +/// +/// let options = CopyOptions::new(); //Initialize default values for CopyOptions +/// copy("dir1/foo.txt", "dir2/bar.txt", &options)?; // Copy dir1/foo.txt to dir2/bar.txt +/// +/// ``` +pub fn copy(from: P, to: Q, options: &CopyOptions) -> Result +where + P: AsRef, + Q: AsRef, +{ + let from = from.as_ref(); + if !from.exists() { + if let Some(msg) = from.to_str() { + let msg = format!("Path \"{}\" does not exist or you don't have access!", msg); + err!(&msg, ErrorKind::NotFound); + } + err!( + "Path does not exist or you don't have access!", + ErrorKind::NotFound + ); + } + + if !from.is_file() { + if let Some(msg) = from.to_str() { + let msg = format!("Path \"{}\" is not a file!", msg); + err!(&msg, ErrorKind::InvalidFile); + } + err!("Path is not a file!", ErrorKind::InvalidFile); + } + + if !options.overwrite && to.as_ref().exists() { + if options.skip_exist { + return Ok(0); + } + + if let Some(msg) = to.as_ref().to_str() { + let msg = format!("Path \"{}\" exists", msg); + err!(&msg, ErrorKind::AlreadyExists); + } + } + + Ok(std::fs::copy(from, to)?) +} + +/// Copies the contents of one file to another file with information about progress. +/// This function will also copy the permission bits of the original file to the +/// destination file. +/// +/// # Errors +/// +/// This function will return an error in the following situations, but is not limited to just +/// these cases: +/// +/// * This `from` path is not a file. +/// * This `from` file does not exist. +/// * The current process does not have the permission to access `from` or write `to`. +/// +/// # Example +/// ```rust,ignore +/// extern crate fs_extra; +/// use fs_extra::file::copy_with_progress; +/// +/// let options = CopyOptions::new(); //Initialize default values for CopyOptions +/// let handle = |process_info: TransitProcess| println!("{}", process_info.total_bytes); +/// +/// // Copy dir1/foo.txt to dir2/foo.txt +/// copy_with_progress("dir1/foo.txt", "dir2/foo.txt", &options, handle)?; +/// +/// ``` +pub fn copy_with_progress( + from: P, + to: Q, + options: &CopyOptions, + mut progress_handler: F, +) -> Result +where + P: AsRef, + Q: AsRef, + F: FnMut(TransitProcess), +{ + let from = from.as_ref(); + if !from.exists() { + if let Some(msg) = from.to_str() { + let msg = format!("Path \"{}\" does not exist or you don't have access!", msg); + err!(&msg, ErrorKind::NotFound); + } + err!( + "Path does not exist or you don't have access!", + ErrorKind::NotFound + ); + } + + if !from.is_file() { + if let Some(msg) = from.to_str() { + let msg = format!("Path \"{}\" is not a file!", msg); + err!(&msg, ErrorKind::InvalidFile); + } + err!("Path is not a file!", ErrorKind::InvalidFile); + } + + if !options.overwrite && to.as_ref().exists() { + if options.skip_exist { + return Ok(0); + } + + if let Some(msg) = to.as_ref().to_str() { + let msg = format!("Path \"{}\" exists", msg); + err!(&msg, ErrorKind::AlreadyExists); + } + } + let mut file_from = File::open(from)?; + let mut buf = vec![0; options.buffer_size]; + let file_size = file_from.metadata()?.len(); + let mut copied_bytes: u64 = 0; + + let mut file_to = File::create(to)?; + while !buf.is_empty() { + match file_from.read(&mut buf) { + Ok(0) => break, + Ok(n) => { + let written_bytes = file_to.write(&buf[..n])?; + if written_bytes != n { + err!("Couldn't write the whole buffer to file", ErrorKind::Other); + } + copied_bytes += n as u64; + let data = TransitProcess { + copied_bytes, + total_bytes: file_size, + }; + progress_handler(data); + } + Err(ref e) if e.kind() == ::std::io::ErrorKind::Interrupted => {} + Err(e) => return Err(::std::convert::From::from(e)), + } + } + Ok(file_size) +} + +/// Moves a file from one place to another. This function will also copy the permission +/// bits of the original file to the destination file. +/// +/// # Errors +/// +/// This function will return an error in the following situations, but is not limited to just +/// these cases: +/// +/// * This `from` path is not a file. +/// * This `from` file does not exist. +/// * The current process does not have the permission to access `from` or write `to`. +/// +/// # Example +/// ```rust,ignore +/// extern crate fs_extra; +/// use fs_extra::file::move_file; +/// +/// let options = CopyOptions::new(); //Initialize default values for CopyOptions +/// move_file("dir1/foo.txt", "dir2/foo.txt", &options)?; // Move dir1/foo.txt to dir2/foo.txt +/// +/// ``` +pub fn move_file(from: P, to: Q, options: &CopyOptions) -> Result +where + P: AsRef, + Q: AsRef, +{ + let mut is_remove = true; + if options.skip_exist && to.as_ref().exists() && !options.overwrite { + is_remove = false; + } + let result = copy(&from, to, options)?; + if is_remove { + remove(from)?; + } + + Ok(result) +} + +/// Moves a file from one place to another with information about progress. +/// This function will also copy the permission bits of the original file to the +/// destination file. +/// +/// # Errors +/// +/// This function will return an error in the following situations, but is not limited to just +/// these cases: +/// +/// * This `from` path is not a file. +/// * This `from` file does not exist. +/// * The current process does not have the permission to access `from` or write `to`. +/// +/// # Example +/// ```rust,ignore +/// extern crate fs_extra; +/// use fs_extra::file::move_file; +/// +/// let options = CopyOptions::new(); //Initialize default values for CopyOptions +/// let handle = |process_info: TransitProcess| println!("{}", process_info.total_bytes); +/// +/// // Move dir1/foo.txt to dir2/foo.txt +/// move_file("dir1/foo.txt", "dir2/foo.txt", &options, handle)?; +/// +/// ``` +pub fn move_file_with_progress( + from: P, + to: Q, + options: &CopyOptions, + progress_handler: F, +) -> Result +where + P: AsRef, + Q: AsRef, + F: FnMut(TransitProcess), +{ + let mut is_remove = true; + if options.skip_exist && to.as_ref().exists() && !options.overwrite { + is_remove = false; + } + let result = copy_with_progress(&from, to, options, progress_handler)?; + if is_remove { + remove(from)?; + } + + Ok(result) +} + +/// Removes a file from the filesystem. +/// +/// # Errors +/// +/// This function will return an error in the following situations, but is not limited to just +/// these cases: +/// +/// * The current process does not have the permission to access `path`. +/// +/// # Example +/// ```rust,ignore +/// extern crate fs_extra; +/// use fs_extra::file::remove; +/// +/// remove("foo.txt" )?; // Remove foo.txt +/// +/// ``` +pub fn remove

(path: P) -> Result<()> +where + P: AsRef, +{ + if path.as_ref().exists() { + Ok(remove_file(path)?) + } else { + Ok(()) + } +} + +/// Read file contents, placing them into `String`. +/// +/// # Errors +/// +/// This function will return an error in the following situations, but is not limited to just +/// these cases: +/// +/// * This `path` is not a file. +/// * This `path` file does not exist. +/// * The current process does not have the permission to access `path`. +/// +/// # Example +/// ```rust,ignore +/// extern crate fs_extra; +/// use fs_extra::file::read_to_string; +/// +/// let file_content = read_to_string("foo.txt" )?; // Get file content from foo.txt +/// println!("{}", file_content); +/// +/// ``` +pub fn read_to_string

(path: P) -> Result +where + P: AsRef, +{ + let path = path.as_ref(); + if path.exists() && !path.is_file() { + if let Some(msg) = path.to_str() { + let msg = format!("Path \"{}\" is not a file!", msg); + err!(&msg, ErrorKind::InvalidFile); + } + err!("Path is not a file!", ErrorKind::InvalidFile); + } + + let mut file = File::open(path)?; + let mut result = String::new(); + file.read_to_string(&mut result)?; + + Ok(result) +} + +/// Write `String` content into file. +/// +/// # Errors +/// +/// This function will return an error in the following situations, but is not limited to just +/// these cases: +/// +/// * This `path` is not a file. +/// * This `path` file does not exist. +/// * The current process does not have the permission to access `path`. +/// +/// # Example +/// ```rust,ignore +/// extern crate fs_extra; +/// use fs_extra::file::read_to_string; +/// +/// write_all("foo.txt", "contents" )?; // Create file foo.txt and send content inside +/// +/// ``` +pub fn write_all

(path: P, content: &str) -> Result<()> +where + P: AsRef, +{ + let path = path.as_ref(); + if path.exists() && !path.is_file() { + if let Some(msg) = path.to_str() { + let msg = format!("Path \"{}\" is not a file!", msg); + err!(&msg, ErrorKind::InvalidFile); + } + err!("Path is not a file!", ErrorKind::InvalidFile); + } + + let mut f = File::create(path)?; + + Ok(f.write_all(content.as_bytes())?) +} diff --git a/vendor/fs_extra/src/lib.rs b/vendor/fs_extra/src/lib.rs new file mode 100644 index 000000000..118643ab8 --- /dev/null +++ b/vendor/fs_extra/src/lib.rs @@ -0,0 +1,802 @@ +macro_rules! err { + ($text:expr, $kind:expr) => { + return Err(Error::new($kind, $text)) + }; + + ($text:expr) => { + err!($text, ErrorKind::Other) + }; +} + +/// The error type for fs_extra operations on files and directories. +pub mod error; +/// This module includes additional methods for working with files. +/// +/// One of the distinguishing features is receipt information +/// about process work with files. +/// +/// # Example +/// ```rust,ignore +/// use std::path::Path; +/// use std::{thread, time}; +/// use std::sync::mpsc::{self, TryRecvError}; +/// +/// extern crate fs_extra; +/// use fs_extra::file::*; +/// use fs_extra::error::*; +/// +/// fn example_copy() -> Result<()> { +/// let path_from = Path::new("./temp"); +/// let path_to = path_from.join("out"); +/// let test_file = (path_from.join("test_file.txt"), path_to.join("test_file.txt")); +/// +/// +/// fs_extra::dir::create_all(&path_from, true)?; +/// fs_extra::dir::create_all(&path_to, true)?; +/// +/// write_all(&test_file.0, "test_data")?; +/// assert!(test_file.0.exists()); +/// assert!(!test_file.1.exists()); +/// +/// +/// let options = CopyOptions { +/// buffer_size: 1, +/// ..Default::default() +/// } +/// let (tx, rx) = mpsc::channel(); +/// thread::spawn(move || { +/// let handler = |process_info: TransitProcess| { +/// tx.send(process_info).unwrap(); +/// thread::sleep(time::Duration::from_millis(500)); +/// }; +/// copy_with_progress(&test_file.0, &test_file.1, &options, handler).unwrap(); +/// assert!(test_file.0.exists()); +/// assert!(test_file.1.exists()); +/// +/// }); +/// loop { +/// match rx.try_recv() { +/// Ok(process_info) => { +/// println!("{} of {} bytes", +/// process_info.copied_bytes, +/// process_info.total_bytes); +/// } +/// Err(TryRecvError::Disconnected) => { +/// println!("finished"); +/// break; +/// } +/// Err(TryRecvError::Empty) => {} +/// } +/// } +/// Ok(()) +/// +/// } +/// +/// +/// fn main() { +/// example_copy(); +/// } +/// +/// ``` +pub mod file; + +/// This module includes additional methods for working with directories. +/// +/// One of the additional features is information +/// about process and recursion operations. +/// +/// # Example +/// ```rust,ignore +/// use std::path::Path; +/// use std::{thread, time}; +/// use std::sync::mpsc::{self, TryRecvError}; +/// +/// extern crate fs_extra; +/// use fs_extra::dir::*; +/// use fs_extra::error::*; +/// +/// fn example_copy() -> Result<()> { +/// +/// let path_from = Path::new("./temp"); +/// let path_to = path_from.join("out"); +/// let test_folder = path_from.join("test_folder"); +/// let dir = test_folder.join("dir"); +/// let sub = dir.join("sub"); +/// let file1 = dir.join("file1.txt"); +/// let file2 = sub.join("file2.txt"); +/// +/// create_all(&sub, true)?; +/// create_all(&path_to, true)?; +/// fs_extra::file::write_all(&file1, "content1")?; +/// fs_extra::file::write_all(&file2, "content2")?; +/// +/// assert!(dir.exists()); +/// assert!(sub.exists()); +/// assert!(file1.exists()); +/// assert!(file2.exists()); +/// +/// +/// let options = CopyOptions { +/// buffer_size: 1, +/// ..Default::default(), +/// }; +/// let (tx, rx) = mpsc::channel(); +/// thread::spawn(move || { +/// let handler = |process_info: TransitProcess| { +/// tx.send(process_info).unwrap(); +/// thread::sleep(time::Duration::from_millis(500)); +/// }; +/// copy_with_progress(&test_folder, &path_to, &options, handler).unwrap(); +/// }); +/// +/// loop { +/// match rx.try_recv() { +/// Ok(process_info) => { +/// println!("{} of {} bytes", +/// process_info.copied_bytes, +/// process_info.total_bytes); +/// } +/// Err(TryRecvError::Disconnected) => { +/// println!("finished"); +/// break; +/// } +/// Err(TryRecvError::Empty) => {} +/// } +/// } +/// Ok(()) +/// +/// } +/// fn main() { +/// example_copy(); +/// } +/// ``` +/// +pub mod dir; + +use crate::error::*; +use std::path::Path; + +/// Copies a list of directories and files to another place recursively. This function will +/// also copy the permission bits of the original files to destination files (not for +/// directories). +/// +/// # Errors +/// +/// This function will return an error in the following situations, but is not limited to just +/// these case: +/// +/// * List `from` contains file or directory does not exist. +/// +/// * List `from` contains file or directory with invalid name. +/// +/// * The current process does not have the permission to access to file from `lists from` or +/// `to`. +/// +/// # Example +/// +/// ```rust,ignore +/// extern crate fs_extra; +/// use fs_extra::dir::copy; +/// +/// let options = dir::CopyOptions::new(); //Initialize default values for CopyOptions +/// +/// // copy dir1 and file1.txt to target/dir1 and target/file1.txt +/// let mut from_paths = Vec::new(); +/// from_paths.push("source/dir1"); +/// from_paths.push("source/file.txt"); +/// copy_items(&from_paths, "target", &options)?; +/// ``` +/// +pub fn copy_items(from: &[P], to: Q, options: &dir::CopyOptions) -> Result +where + P: AsRef, + Q: AsRef, +{ + let mut result: u64 = 0; + if options.content_only { + err!( + "Options 'content_only' not acccess for copy_items function", + ErrorKind::Other + ); + } + for item in from { + let item = item.as_ref(); + if item.is_dir() { + result += dir::copy(item, &to, options)?; + } else if let Some(file_name) = item.file_name() { + if let Some(file_name) = file_name.to_str() { + let file_options = file::CopyOptions { + overwrite: options.overwrite, + skip_exist: options.skip_exist, + ..Default::default() + }; + result += file::copy(item, to.as_ref().join(file_name), &file_options)?; + } + } else { + err!("Invalid file name", ErrorKind::InvalidFileName); + } + } + + Ok(result) +} + +/// A structure which includes information about the current status of copying or moving a directory. +pub struct TransitProcess { + /// Already copied bytes + pub copied_bytes: u64, + /// All the bytes which should be copied or moved (dir size). + pub total_bytes: u64, + /// Copied bytes on this time for file. + pub file_bytes_copied: u64, + /// Size of currently copied file. + pub file_total_bytes: u64, + /// Name of currently copied file. + pub file_name: String, + /// Name of currently copied folder. + pub dir_name: String, + /// Transit state + pub state: dir::TransitState, +} + +impl Clone for TransitProcess { + fn clone(&self) -> TransitProcess { + TransitProcess { + copied_bytes: self.copied_bytes, + total_bytes: self.total_bytes, + file_bytes_copied: self.file_bytes_copied, + file_total_bytes: self.file_total_bytes, + file_name: self.file_name.clone(), + dir_name: self.dir_name.clone(), + state: self.state.clone(), + } + } +} + +/// Copies a list of directories and files to another place recursively, with +/// information about progress. This function will also copy the permission bits of the +/// original files to destination files (not for directories). +/// +/// # Errors +/// +/// This function will return an error in the following situations, but is not limited to just +/// these case: +/// +/// * List `from` contains file or directory does not exist. +/// +/// * List `from` contains file or directory with invalid name. +/// +/// * The current process does not have the permission to access to file from `lists from` or +/// `to`. +/// +/// # Example +/// ```rust,ignore +/// +/// extern crate fs_extra; +/// use fs_extra::dir::copy; +/// +/// let options = dir::CopyOptions::new(); //Initialize default values for CopyOptions +/// let handle = |process_info: TransitProcess| { +/// println!("{}", process_info.total_bytes); +/// fs_extra::dir::TransitProcessResult::ContinueOrAbort +/// } +/// // copy dir1 and file1.txt to target/dir1 and target/file1.txt +/// let mut from_paths = Vec::new(); +/// from_paths.push("source/dir1"); +/// from_paths.push("source/file.txt"); +/// copy_items_with_progress(&from_paths, "target", &options, handle)?; +/// ``` +/// +pub fn copy_items_with_progress( + from: &[P], + to: Q, + options: &dir::CopyOptions, + mut progress_handler: F, +) -> Result +where + P: AsRef, + Q: AsRef, + F: FnMut(TransitProcess) -> dir::TransitProcessResult, +{ + if options.content_only { + err!( + "Options 'content_only' not access for copy_items_with_progress function", + ErrorKind::Other + ); + } + let mut total_size = 0; + let mut list_paths = Vec::new(); + for item in from { + let item = item.as_ref(); + total_size += dir::get_size(item)?; + list_paths.push(item); + } + + let mut result: u64 = 0; + let mut info_process = TransitProcess { + copied_bytes: 0, + total_bytes: total_size, + file_bytes_copied: 0, + file_total_bytes: 0, + file_name: String::new(), + dir_name: String::new(), + state: dir::TransitState::Normal, + }; + + let mut options = options.clone(); + for item in list_paths { + if item.is_dir() { + if let Some(dir_name) = item.components().last() { + if let Ok(dir_name) = dir_name.as_os_str().to_os_string().into_string() { + info_process.dir_name = dir_name; + } else { + err!("Invalid folder from", ErrorKind::InvalidFolder); + } + } else { + err!("Invalid folder from", ErrorKind::InvalidFolder); + } + + let copied_bytes = result; + let dir_options = options.clone(); + let handler = |info: dir::TransitProcess| { + info_process.copied_bytes = copied_bytes + info.copied_bytes; + info_process.state = info.state; + let result = progress_handler(info_process.clone()); + match result { + dir::TransitProcessResult::OverwriteAll => options.overwrite = true, + dir::TransitProcessResult::SkipAll => options.skip_exist = true, + _ => {} + } + result + }; + result += dir::copy_with_progress(item, &to, &dir_options, handler)?; + } else { + let mut file_options = file::CopyOptions { + overwrite: options.overwrite, + skip_exist: options.skip_exist, + buffer_size: options.buffer_size, + }; + + if let Some(file_name) = item.file_name() { + if let Some(file_name) = file_name.to_str() { + info_process.file_name = file_name.to_string(); + } else { + err!("Invalid file name", ErrorKind::InvalidFileName); + } + } else { + err!("Invalid file name", ErrorKind::InvalidFileName); + } + + info_process.file_bytes_copied = 0; + info_process.file_total_bytes = item.metadata()?.len(); + + let copied_bytes = result; + let file_name = to.as_ref().join(info_process.file_name.clone()); + let mut work = true; + + let mut result_copy: Result; + while work { + { + let handler = |info: file::TransitProcess| { + info_process.copied_bytes = copied_bytes + info.copied_bytes; + info_process.file_bytes_copied = info.copied_bytes; + progress_handler(info_process.clone()); + }; + result_copy = + file::copy_with_progress(item, &file_name, &file_options, handler); + } + match result_copy { + Ok(val) => { + result += val; + work = false; + } + Err(err) => match err.kind { + ErrorKind::AlreadyExists => { + let mut info_process = info_process.clone(); + info_process.state = dir::TransitState::Exists; + let user_decide = progress_handler(info_process); + match user_decide { + dir::TransitProcessResult::Overwrite => { + file_options.overwrite = true; + } + dir::TransitProcessResult::OverwriteAll => { + file_options.overwrite = true; + options.overwrite = true; + } + dir::TransitProcessResult::Skip => { + file_options.skip_exist = true; + } + dir::TransitProcessResult::SkipAll => { + file_options.skip_exist = true; + options.skip_exist = true; + } + dir::TransitProcessResult::Retry => {} + dir::TransitProcessResult::ContinueOrAbort => { + let err_msg = err.to_string(); + err!(err_msg.as_str(), err.kind) + } + dir::TransitProcessResult::Abort => { + let err_msg = err.to_string(); + err!(err_msg.as_str(), err.kind) + } + } + } + ErrorKind::PermissionDenied => { + let mut info_process = info_process.clone(); + info_process.state = dir::TransitState::Exists; + let user_decide = progress_handler(info_process); + match user_decide { + dir::TransitProcessResult::Overwrite => { + err!("Overwrite denied for this situation!", ErrorKind::Other); + } + dir::TransitProcessResult::OverwriteAll => { + err!("Overwrite denied for this situation!", ErrorKind::Other); + } + dir::TransitProcessResult::Skip => { + file_options.skip_exist = true; + } + dir::TransitProcessResult::SkipAll => { + file_options.skip_exist = true; + options.skip_exist = true; + } + dir::TransitProcessResult::Retry => {} + dir::TransitProcessResult::ContinueOrAbort => { + let err_msg = err.to_string(); + err!(err_msg.as_str(), err.kind) + } + dir::TransitProcessResult::Abort => { + let err_msg = err.to_string(); + err!(err_msg.as_str(), err.kind) + } + } + } + _ => { + let err_msg = err.to_string(); + err!(err_msg.as_str(), err.kind) + } + }, + } + } + } + } + + Ok(result) +} + +/// Moves a list of directories and files to another place recursively. This function will +/// also copy the permission bits of the original files to destination files (not for +/// directories). +/// +/// # Errors +/// +/// This function will return an error in the following situations, but is not limited to just +/// these case: +/// +/// * List `from` contains file or directory does not exist. +/// +/// * List `from` contains file or directory with invalid name. +/// +/// * The current process does not have the permission to access to file from `lists from` or +/// `to`. +/// +/// # Example +/// +/// ```rust,ignore +/// extern crate fs_extra; +/// use fs_extra::dir::copy; +/// +/// let options = dir::CopyOptions::new(); //Initialize default values for CopyOptions +/// +/// // move dir1 and file1.txt to target/dir1 and target/file1.txt +/// let mut from_paths = Vec::new(); +/// from_paths.push("source/dir1"); +/// from_paths.push("source/file.txt"); +/// move_items(&from_paths, "target", &options)?; +/// ``` +/// +pub fn move_items(from_items: &[P], to: Q, options: &dir::CopyOptions) -> Result +where + P: AsRef, + Q: AsRef, +{ + if options.content_only { + err!( + "Options 'content_only' not access for move_items function", + ErrorKind::Other + ); + } + let mut total_size = 0; + let mut list_paths = Vec::new(); + for item in from_items { + let item = item.as_ref(); + total_size += dir::get_size(item)?; + list_paths.push(item); + } + + let mut result = 0; + let mut info_process = TransitProcess { + copied_bytes: 0, + total_bytes: total_size, + file_bytes_copied: 0, + file_total_bytes: 0, + file_name: String::new(), + dir_name: String::new(), + state: dir::TransitState::Normal, + }; + + for item in list_paths { + if item.is_dir() { + if let Some(dir_name) = item.components().last() { + if let Ok(dir_name) = dir_name.as_os_str().to_os_string().into_string() { + info_process.dir_name = dir_name; + } else { + err!("Invalid folder from", ErrorKind::InvalidFolder); + } + } else { + err!("Invalid folder from", ErrorKind::InvalidFolder); + } + + result += dir::move_dir(item, &to, options)?; + } else { + let file_options = file::CopyOptions { + overwrite: options.overwrite, + skip_exist: options.skip_exist, + buffer_size: options.buffer_size, + }; + + if let Some(file_name) = item.file_name() { + if let Some(file_name) = file_name.to_str() { + info_process.file_name = file_name.to_string(); + } else { + err!("Invalid file name", ErrorKind::InvalidFileName); + } + } else { + err!("Invalid file name", ErrorKind::InvalidFileName); + } + + info_process.file_bytes_copied = 0; + info_process.file_total_bytes = item.metadata()?.len(); + + let file_name = to.as_ref().join(info_process.file_name.clone()); + result += file::move_file(item, &file_name, &file_options)?; + } + } + + Ok(result) +} + +/// Moves a list of directories and files to another place recursively, with +/// information about progress. This function will also copy the permission bits of the +/// original files to destination files (not for directories). +/// +/// # Errors +/// +/// This function will return an error in the following situations, but is not limited to just +/// these case: +/// +/// * List `from` contains file or directory does not exist. +/// +/// * List `from` contains file or directory with invalid name. +/// +/// * The current process does not have the permission to access to file from `lists from` or +/// `to`. +/// +/// # Example +/// +/// ```rust,ignore +/// extern crate fs_extra; +/// use fs_extra::dir::copy; +/// +/// let options = dir::CopyOptions::new(); //Initialize default values for CopyOptions +/// let handle = |process_info: TransitProcess| { +/// println!("{}", process_info.total_bytes); +/// fs_extra::dir::TransitProcessResult::ContinueOrAbort +/// } +/// // move dir1 and file1.txt to target/dir1 and target/file1.txt +/// let mut from_paths = Vec::new(); +/// from_paths.push("source/dir1"); +/// from_paths.push("source/file.txt"); +/// move_items_with_progress(&from_paths, "target", &options, handle)?; +/// ``` +/// +pub fn move_items_with_progress( + from_items: &[P], + to: Q, + options: &dir::CopyOptions, + mut progress_handler: F, +) -> Result +where + P: AsRef, + Q: AsRef, + F: FnMut(TransitProcess) -> dir::TransitProcessResult, +{ + if options.content_only { + err!( + "Options 'content_only' not access for move_items_with_progress function", + ErrorKind::Other + ); + } + let mut total_size = 0; + let mut list_paths = Vec::new(); + for item in from_items { + let item = item.as_ref(); + total_size += dir::get_size(item)?; + list_paths.push(item); + } + + let mut result = 0; + let mut info_process = TransitProcess { + copied_bytes: 0, + total_bytes: total_size, + file_bytes_copied: 0, + file_total_bytes: 0, + file_name: String::new(), + dir_name: String::new(), + state: dir::TransitState::Normal, + }; + let mut options = options.clone(); + + for item in list_paths { + if item.is_dir() { + if let Some(dir_name) = item.components().last() { + if let Ok(dir_name) = dir_name.as_os_str().to_os_string().into_string() { + info_process.dir_name = dir_name; + } else { + err!("Invalid folder from", ErrorKind::InvalidFolder); + } + } else { + err!("Invalid folder from", ErrorKind::InvalidFolder); + } + + let copied_bytes = result; + let dir_options = options.clone(); + let handler = |info: dir::TransitProcess| { + info_process.copied_bytes = copied_bytes + info.copied_bytes; + info_process.state = info.state; + let result = progress_handler(info_process.clone()); + match result { + dir::TransitProcessResult::OverwriteAll => options.overwrite = true, + dir::TransitProcessResult::SkipAll => options.skip_exist = true, + _ => {} + } + result + }; + result += dir::move_dir_with_progress(item, &to, &dir_options, handler)?; + } else { + let mut file_options = file::CopyOptions { + overwrite: options.overwrite, + skip_exist: options.skip_exist, + buffer_size: options.buffer_size, + }; + + if let Some(file_name) = item.file_name() { + if let Some(file_name) = file_name.to_str() { + info_process.file_name = file_name.to_string(); + } else { + err!("Invalid file name", ErrorKind::InvalidFileName); + } + } else { + err!("Invalid file name", ErrorKind::InvalidFileName); + } + + info_process.file_bytes_copied = 0; + info_process.file_total_bytes = item.metadata()?.len(); + + let copied_bytes = result; + let file_name = to.as_ref().join(info_process.file_name.clone()); + let mut work = true; + + let mut result_copy: Result; + while work { + { + let handler = |info: file::TransitProcess| { + info_process.copied_bytes = copied_bytes + info.copied_bytes; + info_process.file_bytes_copied = info.copied_bytes; + progress_handler(info_process.clone()); + }; + result_copy = + file::move_file_with_progress(item, &file_name, &file_options, handler); + } + match result_copy { + Ok(val) => { + result += val; + work = false; + } + Err(err) => match err.kind { + ErrorKind::AlreadyExists => { + let mut info_process = info_process.clone(); + info_process.state = dir::TransitState::Exists; + let user_decide = progress_handler(info_process); + match user_decide { + dir::TransitProcessResult::Overwrite => { + file_options.overwrite = true; + } + dir::TransitProcessResult::OverwriteAll => { + file_options.overwrite = true; + options.overwrite = true; + } + dir::TransitProcessResult::Skip => { + file_options.skip_exist = true; + } + dir::TransitProcessResult::SkipAll => { + file_options.skip_exist = true; + options.skip_exist = true; + } + dir::TransitProcessResult::Retry => {} + dir::TransitProcessResult::ContinueOrAbort => { + let err_msg = err.to_string(); + err!(err_msg.as_str(), err.kind) + } + dir::TransitProcessResult::Abort => { + let err_msg = err.to_string(); + err!(err_msg.as_str(), err.kind) + } + } + } + ErrorKind::PermissionDenied => { + let mut info_process = info_process.clone(); + info_process.state = dir::TransitState::Exists; + let user_decide = progress_handler(info_process); + match user_decide { + dir::TransitProcessResult::Overwrite => { + err!("Overwrite denied for this situation!", ErrorKind::Other); + } + dir::TransitProcessResult::OverwriteAll => { + err!("Overwrite denied for this situation!", ErrorKind::Other); + } + dir::TransitProcessResult::Skip => { + file_options.skip_exist = true; + } + dir::TransitProcessResult::SkipAll => { + file_options.skip_exist = true; + options.skip_exist = true; + } + dir::TransitProcessResult::Retry => {} + dir::TransitProcessResult::ContinueOrAbort => { + let err_msg = err.to_string(); + err!(err_msg.as_str(), err.kind) + } + dir::TransitProcessResult::Abort => { + let err_msg = err.to_string(); + err!(err_msg.as_str(), err.kind) + } + } + } + _ => { + let err_msg = err.to_string(); + err!(err_msg.as_str(), err.kind) + } + }, + } + } + } + } + Ok(result) +} + +/// Removes a list of files or directories. +/// +/// # Example +/// +/// ```rust,ignore +/// let mut from_paths = Vec::new(); +/// from_paths.push("source/dir1"); +/// from_paths.push("source/file.txt"); +/// +/// remove_items(&from_paths).unwrap(); +/// ``` +/// +pub fn remove_items

(from_items: &[P]) -> Result<()> +where + P: AsRef, +{ + for item in from_items { + let item = item.as_ref(); + if item.is_dir() { + dir::remove(item)?; + } else { + file::remove(item)? + } + } + + Ok(()) +} diff --git a/vendor/fs_extra/tests/dir.rs b/vendor/fs_extra/tests/dir.rs new file mode 100644 index 000000000..264706657 --- /dev/null +++ b/vendor/fs_extra/tests/dir.rs @@ -0,0 +1,4824 @@ +use std::collections::HashSet; +use std::fs::{self, read_dir}; +use std::path::{Path, PathBuf}; +use std::sync::mpsc::{self, TryRecvError}; +use std::thread; + +extern crate fs_extra; +use fs_extra::dir::*; +use fs_extra::error::*; + +fn files_eq(file1: P, file2: Q) -> bool +where + P: AsRef, + Q: AsRef, +{ + let content1 = fs_extra::file::read_to_string(file1).unwrap(); + let content2 = fs_extra::file::read_to_string(file2).unwrap(); + content1 == content2 +} + +fn compare_dir(path_from: P, path_to: Q) -> bool +where + P: AsRef, + Q: AsRef, +{ + let mut path_to = path_to.as_ref().to_path_buf(); + match path_from.as_ref().components().last() { + None => panic!("Invalid folder from"), + Some(dir_name) => { + path_to.push(dir_name.as_os_str()); + if !path_to.exists() { + return false; + } + } + } + + for entry in read_dir(&path_from).unwrap() { + let entry = entry.unwrap(); + let path = entry.path(); + if path.is_dir() { + if !compare_dir(path, &path_to) { + return false; + } + } else { + let mut path_to = path_to.to_path_buf(); + match path.file_name() { + None => panic!("No file name"), + Some(file_name) => { + path_to.push(file_name); + if !path_to.exists() { + return false; + } else if !files_eq(&path, path_to.clone()) { + return false; + } + } + } + } + } + + true +} + +// Returns the size of a directory. On Linux with ext4 this can be about 4kB. +// Since the directory size can vary, we need to calculate is dynamically. +fn get_dir_size() -> u64 { + std::fs::create_dir_all("./tests/temp").expect("Couldn't create test folder"); + + std::fs::metadata("./tests/temp") + .expect("Couldn't receive metadata of tests/temp folder") + .len() +} + +#[cfg(unix)] +fn create_file_symlink, Q: AsRef>( + original: P, + link: Q, +) -> std::io::Result<()> { + std::os::unix::fs::symlink(original.as_ref(), link.as_ref()) +} + +#[cfg(windows)] +fn create_file_symlink, Q: AsRef>( + original: P, + link: Q, +) -> std::io::Result<()> { + std::os::windows::fs::symlink_file(original.as_ref(), link.as_ref()) +} + +const TEST_FOLDER: &'static str = "./tests/temp/dir"; + +#[test] +fn it_create_all_work() { + let mut test_dir = PathBuf::from(TEST_FOLDER); + test_dir.push("it_create_all_work"); + test_dir.push("sub_dir"); + if test_dir.exists() { + remove(&test_dir).unwrap(); + } + assert!(!test_dir.exists()); + create_all(&test_dir, false).unwrap(); + assert!(test_dir.exists()); +} + +#[test] +fn it_create_work() { + let mut test_dir = PathBuf::from(TEST_FOLDER); + test_dir.push("it_create_work"); + if !test_dir.exists() { + create_all(&test_dir, false).unwrap(); + } + assert!(test_dir.exists()); + test_dir.push("sub_dir"); + if test_dir.exists() { + remove(&test_dir).unwrap(); + } + create(&test_dir, false).unwrap(); + assert!(test_dir.exists()); +} + +#[test] +fn it_create_exist_folder() { + let mut test_dir = PathBuf::from(TEST_FOLDER); + test_dir.push("it_create_exist_folder"); + test_dir.push("sub"); + if test_dir.exists() { + remove(&test_dir).unwrap(); + } + assert!(!test_dir.exists()); + create_all(&test_dir, false).unwrap(); + assert!(test_dir.exists()); + let mut file_path = test_dir.clone(); + file_path.push("test.txt"); + assert!(!file_path.exists()); + let content = "test_content"; + fs_extra::file::write_all(&file_path, &content).unwrap(); + assert!(file_path.exists()); + + match create(&test_dir, false) { + Ok(_) => panic!("Should be error!"), + Err(err) => match err.kind { + ErrorKind::AlreadyExists => { + assert!(test_dir.exists()); + assert!(file_path.exists()); + let new_content = fs_extra::file::read_to_string(file_path).unwrap(); + assert_eq!(new_content, content); + } + _ => panic!("Wrong error"), + }, + } +} + +#[test] +fn it_create_erase_exist_folder() { + let mut test_dir = PathBuf::from(TEST_FOLDER); + test_dir.push("it_create_erase_exist_folder"); + test_dir.push("sub"); + if test_dir.exists() { + remove(&test_dir).unwrap(); + } + assert!(!test_dir.exists()); + create_all(&test_dir, true).unwrap(); + assert!(test_dir.exists()); + let mut file_path = test_dir.clone(); + file_path.push("test.txt"); + assert!(!file_path.exists()); + fs_extra::file::write_all(&file_path, "test_content").unwrap(); + assert!(file_path.exists()); + + create(&test_dir, true).unwrap(); + assert!(test_dir.exists()); + assert!(!file_path.exists()); +} + +#[test] +fn it_create_all_exist_folder() { + let mut test_dir = PathBuf::from(TEST_FOLDER); + test_dir.push("it_create_all_exist_folder"); + test_dir.push("sub"); + if test_dir.exists() { + remove(&test_dir).unwrap(); + } + assert!(!test_dir.exists()); + create_all(&test_dir, false).unwrap(); + assert!(test_dir.exists()); + let mut file_path = test_dir.clone(); + file_path.push("test.txt"); + assert!(!file_path.exists()); + let content = "test_content"; + fs_extra::file::write_all(&file_path, &content).unwrap(); + assert!(file_path.exists()); + + create_all(&test_dir, false).unwrap(); + assert!(test_dir.exists()); + assert!(file_path.exists()); + let new_content = fs_extra::file::read_to_string(file_path).unwrap(); + assert_eq!(new_content, content); +} + +#[test] +fn it_create_all_erase_exist_folder() { + let mut test_dir = PathBuf::from(TEST_FOLDER); + test_dir.push("it_create_all_erase_exist_folder"); + test_dir.push("sub"); + if test_dir.exists() { + remove(&test_dir).unwrap(); + } + assert!(!test_dir.exists()); + create_all(&test_dir, true).unwrap(); + assert!(test_dir.exists()); + let mut file_path = test_dir.clone(); + file_path.push("test.txt"); + assert!(!file_path.exists()); + fs_extra::file::write_all(&file_path, "test_content").unwrap(); + assert!(file_path.exists()); + + create_all(&test_dir, true).unwrap(); + assert!(test_dir.exists()); + assert!(!file_path.exists()); +} + +#[test] +fn it_remove_work() { + let mut test_dir = PathBuf::from(TEST_FOLDER); + test_dir.push("it_remove_work"); + test_dir.push("sub"); + test_dir.push("second_sub"); + create_all(&test_dir, true).unwrap(); + assert!(test_dir.exists()); + test_dir.pop(); + test_dir.pop(); + remove(&test_dir).unwrap(); + assert!(!test_dir.exists()); +} + +#[test] +fn it_remove_not_exist() { + let mut test_dir = PathBuf::from(TEST_FOLDER); + test_dir.push("it_remove_not_exist"); + test_dir.push("sub"); + assert!(!test_dir.exists()); + match remove(&test_dir) { + Ok(_) => { + assert!(!test_dir.exists()); + } + Err(err) => panic!(err.to_string()), + } +} + +#[test] +fn it_copy_work() { + let mut path_from = PathBuf::from(TEST_FOLDER); + let test_name = "sub"; + path_from.push("it_copy_work"); + let mut path_to = path_from.clone(); + path_to.push("out"); + path_from.push(&test_name); + + create_all(&path_from, true).unwrap(); + assert!(path_from.exists()); + create_all(&path_to, true).unwrap(); + assert!(path_to.exists()); + + let mut file1_path = path_from.clone(); + file1_path.push("test1.txt"); + let content1 = "content1"; + fs_extra::file::write_all(&file1_path, &content1).unwrap(); + assert!(file1_path.exists()); + + let mut sub_dir_path = path_from.clone(); + sub_dir_path.push("sub"); + create(&sub_dir_path, true).unwrap(); + let mut file2_path = sub_dir_path.clone(); + file2_path.push("test2.txt"); + let content2 = "content2"; + fs_extra::file::write_all(&file2_path, &content2).unwrap(); + assert!(file2_path.exists()); + + let options = CopyOptions::new(); + let result = copy(&path_from, &path_to, &options).unwrap(); + + assert_eq!(16, result); + assert!(path_to.exists()); + assert!(path_from.exists()); + assert!(compare_dir(&path_from, &path_to)); +} + +#[test] +fn it_copy_not_folder() { + let mut path_from = PathBuf::from(TEST_FOLDER); + path_from.push("it_copy_not_folder"); + let mut path_to = path_from.clone(); + path_to.push("out"); + path_from.push("sub"); + + create_all(&path_from, true).unwrap(); + assert!(path_from.exists()); + create_all(&path_to, true).unwrap(); + assert!(path_to.exists()); + + let options = CopyOptions::new(); + path_from.push("test.txt"); + fs_extra::file::write_all(&path_from, "test").unwrap(); + + match copy(&path_from, &path_to, &options) { + Err(err) => match err.kind { + ErrorKind::InvalidFolder => { + let wrong_path = format!( + "Path \"{}\" is not a directory!", + path_from.to_str().unwrap() + ); + assert_eq!(wrong_path, err.to_string()); + } + _ => { + panic!("wrong error"); + } + }, + Ok(_) => { + panic!("should be error"); + } + } +} + +#[test] +fn it_copy_source_not_exist() { + let mut path_from = PathBuf::from(TEST_FOLDER); + path_from.push("it_copy_source_not_exist"); + let mut path_to = path_from.clone(); + path_to.push("out"); + path_from.push("sub"); + + assert!(!path_from.exists()); + create_all(&path_to, true).unwrap(); + assert!(path_to.exists()); + + let options = CopyOptions::new(); + match copy(&path_from, &path_to, &options) { + Err(err) => match err.kind { + ErrorKind::NotFound => { + let wrong_path = format!( + "Path \"{}\" does not exist or you don't have \ + access!", + path_from.to_str().unwrap() + ); + assert_eq!(wrong_path, err.to_string()); + } + _ => { + panic!(format!("wrong error {}", err.to_string())); + } + }, + Ok(_) => { + panic!("should be error"); + } + } +} + +#[test] +fn it_copy_exist_overwrite() { + let mut path_from = PathBuf::from(TEST_FOLDER); + let test_name = "sub"; + path_from.push("it_copy_exist_overwrite"); + let mut path_to = path_from.clone(); + path_to.push("out"); + path_from.push(&test_name); + let same_file = "test.txt"; + + create_all(&path_from, true).unwrap(); + assert!(path_from.exists()); + create_all(&path_to, true).unwrap(); + assert!(path_to.exists()); + + let mut file1_path = path_from.clone(); + file1_path.push(same_file); + let content1 = "content1"; + fs_extra::file::write_all(&file1_path, &content1).unwrap(); + assert!(file1_path.exists()); + + let mut sub_dir_path = path_from.clone(); + sub_dir_path.push("sub"); + create(&sub_dir_path, true).unwrap(); + let mut file2_path = sub_dir_path.clone(); + file2_path.push("test2.txt"); + let content2 = "content2"; + fs_extra::file::write_all(&file2_path, &content2).unwrap(); + assert!(file2_path.exists()); + + let mut exist_path = path_to.clone(); + exist_path.push(&test_name); + create(&exist_path, true).unwrap(); + assert!(exist_path.exists()); + exist_path.push(same_file); + let exist_content = "exist content"; + assert_ne!(exist_content, content1); + fs_extra::file::write_all(&exist_path, exist_content).unwrap(); + assert!(exist_path.exists()); + + let mut options = CopyOptions::new(); + options.overwrite = true; + copy(&path_from, &path_to, &options).unwrap(); + + assert!(exist_path.exists()); + assert!(files_eq(file1_path, exist_path)); + assert!(path_to.exists()); + assert!(compare_dir(&path_from, &path_to)); +} + +#[test] +fn it_copy_exist_not_overwrite() { + let test_name = "sub"; + let mut path_from = PathBuf::from(TEST_FOLDER); + path_from.push("it_copy_exist_not_overwrite"); + let mut path_to = path_from.clone(); + path_to.push("out"); + path_from.push(test_name); + let same_file = "test.txt"; + + create_all(&path_from, true).unwrap(); + assert!(path_from.exists()); + create_all(&path_to, true).unwrap(); + assert!(path_to.exists()); + + let mut file1_path = path_from.clone(); + file1_path.push(same_file); + let content1 = "content1"; + fs_extra::file::write_all(&file1_path, &content1).unwrap(); + assert!(file1_path.exists()); + + let mut exist_path = path_to.clone(); + exist_path.push(&test_name); + create(&exist_path, true).unwrap(); + assert!(exist_path.exists()); + exist_path.push(same_file); + let exist_content = "exist content"; + assert_ne!(exist_content, content1); + fs_extra::file::write_all(&exist_path, exist_content).unwrap(); + assert!(exist_path.exists()); + + let options = CopyOptions::new(); + match copy(&path_from, &path_to, &options) { + Err(err) => match err.kind { + ErrorKind::AlreadyExists => { + let wrong_path = format!("Path \"{}\" exists", exist_path.to_str().unwrap()); + assert_eq!(wrong_path, err.to_string()); + } + _ => { + panic!(format!("wrong error {}", err.to_string())); + } + }, + Ok(_) => { + panic!("should be error"); + } + } +} + +#[test] +fn it_copy_exist_skip_exist() { + let mut path_from = PathBuf::from(TEST_FOLDER); + let test_name = "sub"; + path_from.push("it_copy_exist_skip_exist"); + let mut path_to = path_from.clone(); + path_to.push("out"); + path_from.push(&test_name); + let same_file = "test.txt"; + + create_all(&path_from, true).unwrap(); + assert!(path_from.exists()); + create_all(&path_to, true).unwrap(); + assert!(path_to.exists()); + + let mut file1_path = path_from.clone(); + file1_path.push(same_file); + let content1 = "content1"; + fs_extra::file::write_all(&file1_path, &content1).unwrap(); + assert!(file1_path.exists()); + + let mut sub_dir_path = path_from.clone(); + sub_dir_path.push("sub"); + create(&sub_dir_path, true).unwrap(); + let mut file2_path = sub_dir_path.clone(); + file2_path.push("test2.txt"); + let content2 = "content2"; + fs_extra::file::write_all(&file2_path, &content2).unwrap(); + assert!(file2_path.exists()); + + let mut exist_path = path_to.clone(); + exist_path.push(&test_name); + create(&exist_path, true).unwrap(); + assert!(exist_path.exists()); + exist_path.push(same_file); + let exist_content = "exist content"; + assert_ne!(exist_content, content1); + fs_extra::file::write_all(&exist_path, exist_content).unwrap(); + assert!(exist_path.exists()); + + let mut options = CopyOptions::new(); + options.skip_exist = true; + copy(&path_from, &path_to, &options).unwrap(); + + assert!(exist_path.exists()); + assert!(!files_eq(file1_path, &exist_path)); + assert_eq!( + fs_extra::file::read_to_string(exist_path).unwrap(), + exist_content + ); + + assert!(path_to.exists()); + assert!(!compare_dir(&path_from, &path_to)); +} + +#[test] +fn it_copy_exist_overwrite_and_skip_exist() { + let mut path_from = PathBuf::from(TEST_FOLDER); + let test_name = "sub"; + path_from.push("it_copy_exist_overwrite_and_skip_exist"); + let mut path_to = path_from.clone(); + path_to.push("out"); + path_from.push(&test_name); + let same_file = "test.txt"; + + create_all(&path_from, true).unwrap(); + assert!(path_from.exists()); + create_all(&path_to, true).unwrap(); + assert!(path_to.exists()); + + let mut file1_path = path_from.clone(); + file1_path.push(same_file); + let content1 = "content1"; + fs_extra::file::write_all(&file1_path, &content1).unwrap(); + assert!(file1_path.exists()); + + let mut sub_dir_path = path_from.clone(); + sub_dir_path.push("sub"); + create(&sub_dir_path, true).unwrap(); + let mut file2_path = sub_dir_path.clone(); + file2_path.push("test2.txt"); + let content2 = "content2"; + fs_extra::file::write_all(&file2_path, &content2).unwrap(); + assert!(file2_path.exists()); + + let mut exist_path = path_to.clone(); + exist_path.push(&test_name); + create(&exist_path, true).unwrap(); + assert!(exist_path.exists()); + exist_path.push(same_file); + let exist_content = "exist content"; + assert_ne!(exist_content, content1); + fs_extra::file::write_all(&exist_path, exist_content).unwrap(); + assert!(exist_path.exists()); + + let mut options = CopyOptions::new(); + options.overwrite = true; + options.skip_exist = true; + copy(&path_from, &path_to, &options).unwrap(); + + assert!(exist_path.exists()); + assert!(files_eq(file1_path, exist_path)); + assert!(path_to.exists()); + assert!(compare_dir(&path_from, &path_to)); +} + +#[test] +fn it_copy_using_first_levels() { + let test_dir = Path::new(TEST_FOLDER).join("it_copy_using_first_levels"); + let path_to = test_dir.join("out"); + let d_level_1 = (test_dir.join("d_level_1"), path_to.join("d_level_1")); + let d_level_2 = (d_level_1.0.join("d_level_2"), d_level_1.1.join("d_level_2")); + let d_level_3 = (d_level_2.0.join("d_level_3"), d_level_2.1.join("d_level_3")); + let d_level_4 = (d_level_3.0.join("d_level_4"), d_level_3.1.join("d_level_4")); + let d_level_5 = (d_level_4.0.join("d_level_5"), d_level_4.1.join("d_level_5")); + + let file1 = (d_level_1.0.join("file1.txt"), d_level_1.1.join("file1.txt")); + let file2 = (d_level_2.0.join("file2.txt"), d_level_2.1.join("file2.txt")); + let file3 = (d_level_3.0.join("file3.txt"), d_level_3.1.join("file3.txt")); + let file4 = (d_level_4.0.join("file4.txt"), d_level_4.1.join("file4.txt")); + let file5 = (d_level_5.0.join("file5.txt"), d_level_5.1.join("file5.txt")); + + create_all(&d_level_1.0, true).unwrap(); + create_all(&d_level_2.0, true).unwrap(); + create_all(&d_level_3.0, true).unwrap(); + create_all(&d_level_4.0, true).unwrap(); + create_all(&d_level_5.0, true).unwrap(); + create_all(&path_to, true).unwrap(); + + assert!(path_to.exists()); + assert!(d_level_1.0.exists()); + assert!(d_level_2.0.exists()); + assert!(d_level_3.0.exists()); + assert!(d_level_4.0.exists()); + assert!(d_level_5.0.exists()); + + assert!(!d_level_1.1.exists()); + assert!(!d_level_2.1.exists()); + assert!(!d_level_3.1.exists()); + assert!(!d_level_4.1.exists()); + assert!(!d_level_5.1.exists()); + + fs_extra::file::write_all(&file1.0, "content1").unwrap(); + fs_extra::file::write_all(&file2.0, "content2").unwrap(); + fs_extra::file::write_all(&file3.0, "content3").unwrap(); + fs_extra::file::write_all(&file4.0, "content4").unwrap(); + fs_extra::file::write_all(&file5.0, "content5").unwrap(); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file3.0.exists()); + assert!(file4.0.exists()); + assert!(file5.0.exists()); + + assert!(!file1.1.exists()); + assert!(!file2.1.exists()); + assert!(!file3.1.exists()); + assert!(!file4.1.exists()); + assert!(!file5.1.exists()); + + let mut options = CopyOptions::new(); + options.depth = 1; + let result = copy(&d_level_1.0, path_to, &options).unwrap(); + + assert_eq!(8, result); + + assert!(d_level_1.0.exists()); + assert!(d_level_2.0.exists()); + assert!(d_level_3.0.exists()); + assert!(d_level_4.0.exists()); + assert!(d_level_5.0.exists()); + + assert!(d_level_1.1.exists()); + assert!(d_level_2.1.exists()); + assert!(!d_level_3.1.exists()); + assert!(!d_level_4.1.exists()); + assert!(!d_level_5.1.exists()); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file3.0.exists()); + assert!(file4.0.exists()); + assert!(file5.0.exists()); + + assert!(file1.1.exists()); + assert!(!file2.1.exists()); + assert!(!file3.1.exists()); + assert!(!file4.1.exists()); + assert!(!file5.1.exists()); + assert!(files_eq(&file1.0, &file1.1)); +} + +#[test] +fn it_copy_using_four_levels() { + let test_dir = Path::new(TEST_FOLDER).join("it_copy_using_four_levels"); + let path_to = test_dir.join("out"); + let d_level_1 = (test_dir.join("d_level_1"), path_to.join("d_level_1")); + let d_level_2 = (d_level_1.0.join("d_level_2"), d_level_1.1.join("d_level_2")); + let d_level_3 = (d_level_2.0.join("d_level_3"), d_level_2.1.join("d_level_3")); + let d_level_4 = (d_level_3.0.join("d_level_4"), d_level_3.1.join("d_level_4")); + let d_level_5 = (d_level_4.0.join("d_level_5"), d_level_4.1.join("d_level_5")); + + let file1 = (d_level_1.0.join("file1.txt"), d_level_1.1.join("file1.txt")); + let file2 = (d_level_2.0.join("file2.txt"), d_level_2.1.join("file2.txt")); + let file3 = (d_level_3.0.join("file3.txt"), d_level_3.1.join("file3.txt")); + let file4 = (d_level_4.0.join("file4.txt"), d_level_4.1.join("file4.txt")); + let file5 = (d_level_5.0.join("file5.txt"), d_level_5.1.join("file5.txt")); + + create_all(&d_level_1.0, true).unwrap(); + create_all(&d_level_2.0, true).unwrap(); + create_all(&d_level_3.0, true).unwrap(); + create_all(&d_level_4.0, true).unwrap(); + create_all(&d_level_5.0, true).unwrap(); + create_all(&path_to, true).unwrap(); + + assert!(path_to.exists()); + assert!(d_level_1.0.exists()); + assert!(d_level_2.0.exists()); + assert!(d_level_3.0.exists()); + assert!(d_level_4.0.exists()); + assert!(d_level_5.0.exists()); + + assert!(!d_level_1.1.exists()); + assert!(!d_level_2.1.exists()); + assert!(!d_level_3.1.exists()); + assert!(!d_level_4.1.exists()); + assert!(!d_level_5.1.exists()); + + fs_extra::file::write_all(&file1.0, "content1").unwrap(); + fs_extra::file::write_all(&file2.0, "content2").unwrap(); + fs_extra::file::write_all(&file3.0, "content3").unwrap(); + fs_extra::file::write_all(&file4.0, "content4").unwrap(); + fs_extra::file::write_all(&file5.0, "content5").unwrap(); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file3.0.exists()); + assert!(file4.0.exists()); + assert!(file5.0.exists()); + + assert!(!file1.1.exists()); + assert!(!file2.1.exists()); + assert!(!file3.1.exists()); + assert!(!file4.1.exists()); + assert!(!file5.1.exists()); + + let mut options = CopyOptions::new(); + options.depth = 4; + let result = copy(&d_level_1.0, path_to, &options).unwrap(); + + assert_eq!(32, result); + + assert!(d_level_1.0.exists()); + assert!(d_level_2.0.exists()); + assert!(d_level_3.0.exists()); + assert!(d_level_4.0.exists()); + assert!(d_level_5.0.exists()); + + assert!(d_level_1.1.exists()); + assert!(d_level_2.1.exists()); + assert!(d_level_3.1.exists()); + assert!(d_level_4.1.exists()); + assert!(d_level_5.1.exists()); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file3.0.exists()); + assert!(file4.0.exists()); + assert!(file5.0.exists()); + + assert!(file1.1.exists()); + assert!(file2.1.exists()); + assert!(file3.1.exists()); + assert!(file4.1.exists()); + assert!(!file5.1.exists()); + + assert!(files_eq(&file1.0, &file1.1)); + assert!(files_eq(&file2.0, &file2.1)); + assert!(files_eq(&file3.0, &file3.1)); + assert!(files_eq(&file4.0, &file4.1)); +} +#[test] +fn it_copy_content_only_option() { + let test_dir = Path::new(TEST_FOLDER).join("it_copy_content_only_option"); + let path_to = test_dir.join("out"); + let d_level_1 = (test_dir.join("d_level_1"), path_to.clone()); + let d_level_2 = (d_level_1.0.join("d_level_2"), d_level_1.1.join("d_level_2")); + let d_level_3 = (d_level_2.0.join("d_level_3"), d_level_2.1.join("d_level_3")); + + let file1 = (d_level_1.0.join("file1.txt"), d_level_1.1.join("file1.txt")); + let file2 = (d_level_2.0.join("file2.txt"), d_level_2.1.join("file2.txt")); + let file3 = (d_level_3.0.join("file3.txt"), d_level_3.1.join("file3.txt")); + + create_all(&d_level_1.0, true).unwrap(); + create_all(&d_level_2.0, true).unwrap(); + create_all(&d_level_3.0, true).unwrap(); + create_all(&path_to, true).unwrap(); + + assert!(path_to.exists()); + assert!(d_level_1.0.exists()); + assert!(d_level_2.0.exists()); + assert!(d_level_3.0.exists()); + + assert!(!d_level_2.1.exists()); + assert!(!d_level_3.1.exists()); + + fs_extra::file::write_all(&file1.0, "content1").unwrap(); + fs_extra::file::write_all(&file2.0, "content2").unwrap(); + fs_extra::file::write_all(&file3.0, "content3").unwrap(); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file3.0.exists()); + + assert!(!file1.1.exists()); + assert!(!file2.1.exists()); + assert!(!file3.1.exists()); + + let mut options = CopyOptions::new(); + options.content_only = true; + let result = copy(&d_level_1.0, path_to, &options).unwrap(); + + assert_eq!(24, result); + + assert!(d_level_1.0.exists()); + assert!(d_level_2.0.exists()); + assert!(d_level_3.0.exists()); + + assert!(d_level_1.1.exists()); + assert!(d_level_2.1.exists()); + assert!(d_level_3.1.exists()); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file3.0.exists()); + + assert!(file1.1.exists()); + assert!(file2.1.exists()); + assert!(file3.1.exists()); + + assert!(files_eq(&file1.0, &file1.1)); + assert!(files_eq(&file2.0, &file2.1)); + assert!(files_eq(&file3.0, &file3.1)); +} + +#[test] +fn it_copy_progress_work() { + let mut path_from = PathBuf::from(TEST_FOLDER); + let test_name = "sub"; + path_from.push("it_copy_progress_work"); + let mut path_to = path_from.clone(); + path_to.push("out"); + path_from.push(&test_name); + + create_all(&path_from, true).unwrap(); + assert!(path_from.exists()); + create_all(&path_to, true).unwrap(); + assert!(path_to.exists()); + + let mut file1_path = path_from.clone(); + file1_path.push("test1.txt"); + let content1 = "content"; + fs_extra::file::write_all(&file1_path, &content1).unwrap(); + assert!(file1_path.exists()); + + let mut sub_dir_path = path_from.clone(); + sub_dir_path.push("sub"); + create(&sub_dir_path, true).unwrap(); + let mut file2_path = sub_dir_path.clone(); + file2_path.push("test2.txt"); + let content2 = "content2"; + fs_extra::file::write_all(&file2_path, &content2).unwrap(); + assert!(file2_path.exists()); + + let mut options = CopyOptions::new(); + + options.buffer_size = 1; + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let func_test = |process_info: TransitProcess| { + tx.send(process_info).unwrap(); + TransitProcessResult::ContinueOrAbort + }; + let result = copy_with_progress(&path_from, &path_to, &options, func_test).unwrap(); + + assert_eq!(15, result); + assert!(path_to.exists()); + assert!(compare_dir(&path_from, &path_to)); + }) + .join(); + + loop { + match rx.try_recv() { + Ok(process_info) => { + if process_info.file_name == "test2.txt" { + assert_eq!(8, process_info.file_total_bytes); + assert_eq!(get_dir_size() * 2 + 15, process_info.total_bytes); + } else if process_info.file_name == "test1.txt" { + assert_eq!(7, process_info.file_total_bytes); + assert_eq!(get_dir_size() * 2 + 15, process_info.total_bytes); + } else { + panic!("Unknow file name!"); + } + } + Err(TryRecvError::Disconnected) => { + break; + } + Err(TryRecvError::Empty) => {} + } + } + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } +} + +#[test] +fn it_copy_with_progress_not_folder() { + let mut path_from = PathBuf::from(TEST_FOLDER); + path_from.push("it_copy_with_progress_not_folder"); + let mut path_to = path_from.clone(); + path_to.push("out"); + path_from.push("sub"); + + create_all(&path_from, true).unwrap(); + assert!(path_from.exists()); + create_all(&path_to, true).unwrap(); + assert!(path_to.exists()); + + let options = CopyOptions::new(); + path_from.push("test.txt"); + fs_extra::file::write_all(&path_from, "test").unwrap(); + let func_test = |process_info: TransitProcess| { + match process_info.state { + TransitState::NoAccess => {} + _ => panic!("Error not should be!"), + }; + TransitProcessResult::ContinueOrAbort + }; + match copy_with_progress(&path_from, &path_to, &options, func_test) { + Err(err) => match err.kind { + ErrorKind::InvalidFolder => { + let wrong_path = format!( + "Path \"{}\" is not a directory!", + path_from.to_str().unwrap() + ); + assert_eq!(wrong_path, err.to_string()); + } + _ => { + panic!("wrong error"); + } + }, + Ok(_) => { + panic!("should be error"); + } + } +} + +#[test] +fn it_copy_with_progress_work_dif_buf_size() { + let mut path_from = PathBuf::from(TEST_FOLDER); + let test_name = "sub"; + path_from.push("it_copy_with_progress_work_dif_buf_size"); + let mut path_to = path_from.clone(); + path_to.push("out"); + path_from.push(&test_name); + + create_all(&path_from, true).unwrap(); + assert!(path_from.exists()); + create_all(&path_to, true).unwrap(); + assert!(path_to.exists()); + + let mut file1_path = path_from.clone(); + file1_path.push("test1.txt"); + let content1 = "content1"; + fs_extra::file::write_all(&file1_path, &content1).unwrap(); + assert!(file1_path.exists()); + + let mut sub_dir_path = path_from.clone(); + sub_dir_path.push("sub"); + create(&sub_dir_path, true).unwrap(); + let mut file2_path = sub_dir_path.clone(); + file2_path.push("test2.txt"); + let content2 = "content2"; + fs_extra::file::write_all(&file2_path, &content2).unwrap(); + assert!(file2_path.exists()); + + let mut options = CopyOptions::new(); + + options.buffer_size = 1; + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let func_test = |process_info: TransitProcess| { + tx.send(process_info).unwrap(); + TransitProcessResult::ContinueOrAbort + }; + + let result = copy_with_progress(&path_from, &path_to, &options, func_test).unwrap(); + + assert_eq!(16, result); + assert!(path_to.exists()); + assert!(compare_dir(&path_from, &path_to)); + + let mut options = CopyOptions::new(); + options.buffer_size = 2; + options.overwrite = true; + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let func_test = |process_info: TransitProcess| { + tx.send(process_info).unwrap(); + TransitProcessResult::ContinueOrAbort + }; + + let result = copy_with_progress(&path_from, &path_to, &options, func_test).unwrap(); + + assert_eq!(16, result); + assert!(path_to.exists()); + assert!(compare_dir(&path_from, &path_to)); + }) + .join(); + for i in 1..5 { + let process_info: TransitProcess = rx.recv().unwrap(); + assert_eq!(i * 2, process_info.file_bytes_copied); + assert_eq!(i * 2, process_info.copied_bytes); + assert_eq!(8, process_info.file_total_bytes); + assert_eq!(get_dir_size() * 2 + 16, process_info.total_bytes); + } + for i in 1..5 { + let process_info: TransitProcess = rx.recv().unwrap(); + assert_eq!(i * 2 + 8, process_info.copied_bytes); + assert_eq!(i * 2, process_info.file_bytes_copied); + assert_eq!(8, process_info.file_total_bytes); + assert_eq!(get_dir_size() * 2 + 16, process_info.total_bytes); + } + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } + }) + .join(); + + for i in 1..9 { + let process_info: TransitProcess = rx.recv().unwrap(); + assert_eq!(i, process_info.file_bytes_copied); + assert_eq!(i, process_info.copied_bytes); + assert_eq!(8, process_info.file_total_bytes); + assert_eq!(get_dir_size() * 2 + 16, process_info.total_bytes); + } + for i in 1..9 { + let process_info: TransitProcess = rx.recv().unwrap(); + assert_eq!(i + 8, process_info.copied_bytes); + assert_eq!(i, process_info.file_bytes_copied); + assert_eq!(8, process_info.file_total_bytes); + assert_eq!(get_dir_size() * 2 + 16, process_info.total_bytes); + } + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } +} +#[test] +fn it_copy_with_progress_source_not_exist() { + let mut path_from = PathBuf::from(TEST_FOLDER); + path_from.push("it_copy_with_progress_source_not_exist"); + let mut path_to = path_from.clone(); + path_to.push("out"); + path_from.push("sub"); + + assert!(!path_from.exists()); + create_all(&path_to, true).unwrap(); + assert!(path_to.exists()); + + let options = CopyOptions::new(); + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let func_test = |process_info: TransitProcess| { + tx.send(process_info).unwrap(); + TransitProcessResult::ContinueOrAbort + }; + + match copy_with_progress(&path_from, &path_to, &options, func_test) { + Err(err) => match err.kind { + ErrorKind::NotFound => { + let wrong_path = format!( + "Path \"{}\" does not exist or you don't \ + have access!", + path_from.to_str().unwrap() + ); + assert_eq!(wrong_path, err.to_string()); + } + _ => { + panic!(format!("wrong error {}", err.to_string())); + } + }, + Ok(_) => { + panic!("should be error"); + } + } + }) + .join(); + match result { + Ok(_) => {} + Err(err) => panic!(err), + } + + match rx.recv() { + Err(_) => {} + _ => panic!("should be error"), + } +} + +#[test] +fn it_copy_with_progress_exist_overwrite() { + let mut path_from = PathBuf::from(TEST_FOLDER); + let test_name = "sub"; + path_from.push("it_copy_with_progress_exist_overwrite"); + let mut path_to = path_from.clone(); + path_to.push("out"); + path_from.push(&test_name); + + create_all(&path_from, true).unwrap(); + assert!(path_from.exists()); + create_all(&path_to, true).unwrap(); + assert!(path_to.exists()); + + let mut file1_path = path_from.clone(); + file1_path.push("test1.txt"); + let content1 = "content"; + fs_extra::file::write_all(&file1_path, &content1).unwrap(); + assert!(file1_path.exists()); + + let mut sub_dir_path = path_from.clone(); + sub_dir_path.push("sub"); + create(&sub_dir_path, true).unwrap(); + let mut file2_path = sub_dir_path.clone(); + file2_path.push("test2.txt"); + let content2 = "content2"; + fs_extra::file::write_all(&file2_path, &content2).unwrap(); + assert!(file2_path.exists()); + + let mut options = CopyOptions::new(); + copy(&path_from, &path_to, &options).unwrap(); + fs_extra::file::write_all(&file2_path, "another conntent").unwrap(); + + options.buffer_size = 1; + options.overwrite = true; + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let func_test = |process_info: TransitProcess| { + tx.send(process_info).unwrap(); + TransitProcessResult::ContinueOrAbort + }; + + let result = copy_with_progress(&path_from, &path_to, &options, func_test).unwrap(); + + assert_eq!(23, result); + assert!(path_to.exists()); + assert!(compare_dir(&path_from, &path_to)); + }) + .join(); + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } + + match rx.recv() { + Err(_) => panic!("Errors should not be!"), + _ => {} + } +} + +#[test] +fn it_copy_with_progress_exist_not_overwrite() { + let mut path_from = PathBuf::from(TEST_FOLDER); + let test_name = "sub"; + path_from.push("it_copy_with_progress_exist_not_overwrite"); + let mut path_to = path_from.clone(); + path_to.push("out"); + path_from.push(&test_name); + + create_all(&path_from, true).unwrap(); + assert!(path_from.exists()); + create_all(&path_to, true).unwrap(); + assert!(path_to.exists()); + + let mut file1_path = path_from.clone(); + file1_path.push("test1.txt"); + let content1 = "content"; + fs_extra::file::write_all(&file1_path, &content1).unwrap(); + assert!(file1_path.exists()); + + let mut sub_dir_path = path_from.clone(); + sub_dir_path.push("sub"); + create(&sub_dir_path, true).unwrap(); + let mut file2_path = sub_dir_path.clone(); + file2_path.push("test2.txt"); + let content2 = "content2"; + fs_extra::file::write_all(&file2_path, &content2).unwrap(); + assert!(file2_path.exists()); + + let mut options = CopyOptions::new(); + copy(&path_from, &path_to, &options).unwrap(); + + options.buffer_size = 1; + let func_test = |process_info: TransitProcess| { + match process_info.state { + TransitState::Exists => {} + _ => panic!("Error not should be!"), + }; + TransitProcessResult::ContinueOrAbort + }; + let result = copy_with_progress(&path_from, &path_to, &options, func_test); + match result { + Ok(_) => panic!("Should be error!"), + Err(err) => match err.kind { + ErrorKind::AlreadyExists => {} + _ => panic!("Wrong wrror"), + }, + } +} + +#[test] +fn it_copy_with_progress_exist_skip_exist() { + let mut path_from = PathBuf::from(TEST_FOLDER); + let test_name = "sub"; + path_from.push("it_copy_with_progress_exist_skip_exist"); + let mut path_to = path_from.clone(); + path_to.push("out"); + path_from.push(&test_name); + + create_all(&path_from, true).unwrap(); + assert!(path_from.exists()); + create_all(&path_to, true).unwrap(); + assert!(path_to.exists()); + + let mut file1_path = path_from.clone(); + file1_path.push("test1.txt"); + let content1 = "content"; + fs_extra::file::write_all(&file1_path, &content1).unwrap(); + assert!(file1_path.exists()); + + let mut sub_dir_path = path_from.clone(); + sub_dir_path.push("sub"); + create(&sub_dir_path, true).unwrap(); + let mut file2_path = sub_dir_path.clone(); + file2_path.push("test2.txt"); + let content2 = "content2"; + fs_extra::file::write_all(&file2_path, &content2).unwrap(); + assert!(file2_path.exists()); + + let mut options = CopyOptions::new(); + copy(&path_from, &path_to, &options).unwrap(); + + fs_extra::file::write_all(&file2_path, "another conntent").unwrap(); + options.buffer_size = 1; + options.skip_exist = true; + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let func_test = |process_info: TransitProcess| { + tx.send(process_info).unwrap(); + TransitProcessResult::ContinueOrAbort + }; + let result = copy_with_progress(&path_from, &path_to, &options, func_test).unwrap(); + + assert_eq!(0, result); + assert!(path_to.exists()); + assert!(!compare_dir(&path_from, &path_to)); + }) + .join(); + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } + + match rx.recv() { + Err(_) => {} + _ => panic!("should be error"), + } +} + +#[test] +fn it_copy_with_progress_exist_overwrite_and_skip_exist() { + let mut path_from = PathBuf::from(TEST_FOLDER); + let test_name = "sub"; + path_from.push("it_copy_with_progress_exist_overwrite_and_skip_exist"); + let mut path_to = path_from.clone(); + path_to.push("out"); + path_from.push(&test_name); + + create_all(&path_from, true).unwrap(); + assert!(path_from.exists()); + create_all(&path_to, true).unwrap(); + assert!(path_to.exists()); + + let mut file1_path = path_from.clone(); + file1_path.push("test1.txt"); + let content1 = "content"; + fs_extra::file::write_all(&file1_path, &content1).unwrap(); + assert!(file1_path.exists()); + + let mut sub_dir_path = path_from.clone(); + sub_dir_path.push("sub"); + create(&sub_dir_path, true).unwrap(); + let mut file2_path = sub_dir_path.clone(); + file2_path.push("test2.txt"); + let content2 = "content2"; + fs_extra::file::write_all(&file2_path, &content2).unwrap(); + assert!(file2_path.exists()); + + let mut options = CopyOptions::new(); + copy(&path_from, &path_to, &options).unwrap(); + fs_extra::file::write_all(&file2_path, "another conntent").unwrap(); + + options.buffer_size = 1; + options.overwrite = true; + options.skip_exist = true; + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let func_test = |process_info: TransitProcess| { + tx.send(process_info).unwrap(); + TransitProcessResult::ContinueOrAbort + }; + + let result = copy_with_progress(&path_from, &path_to, &options, func_test).unwrap(); + + assert_eq!(23, result); + assert!(path_to.exists()); + assert!(compare_dir(&path_from, &path_to)); + }) + .join(); + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } + rx.recv().unwrap(); +} + +#[test] +fn it_copy_with_progress_using_first_levels() { + let test_dir = Path::new(TEST_FOLDER).join("it_copy_with_progress_using_first_levels"); + let path_to = test_dir.join("out"); + let d_level_1 = (test_dir.join("d_level_1"), path_to.join("d_level_1")); + let d_level_2 = (d_level_1.0.join("d_level_2"), d_level_1.1.join("d_level_2")); + let d_level_3 = (d_level_2.0.join("d_level_3"), d_level_2.1.join("d_level_3")); + let d_level_4 = (d_level_3.0.join("d_level_4"), d_level_3.1.join("d_level_4")); + let d_level_5 = (d_level_4.0.join("d_level_5"), d_level_4.1.join("d_level_5")); + + let file1 = (d_level_1.0.join("file1.txt"), d_level_1.1.join("file1.txt")); + let file2 = (d_level_2.0.join("file2.txt"), d_level_2.1.join("file2.txt")); + let file3 = (d_level_3.0.join("file3.txt"), d_level_3.1.join("file3.txt")); + let file4 = (d_level_4.0.join("file4.txt"), d_level_4.1.join("file4.txt")); + let file5 = (d_level_5.0.join("file5.txt"), d_level_5.1.join("file5.txt")); + + create_all(&d_level_1.0, true).unwrap(); + create_all(&d_level_2.0, true).unwrap(); + create_all(&d_level_3.0, true).unwrap(); + create_all(&d_level_4.0, true).unwrap(); + create_all(&d_level_5.0, true).unwrap(); + create_all(&path_to, true).unwrap(); + + assert!(path_to.exists()); + assert!(d_level_1.0.exists()); + assert!(d_level_2.0.exists()); + assert!(d_level_3.0.exists()); + assert!(d_level_4.0.exists()); + assert!(d_level_5.0.exists()); + + assert!(!d_level_1.1.exists()); + assert!(!d_level_2.1.exists()); + assert!(!d_level_3.1.exists()); + assert!(!d_level_4.1.exists()); + assert!(!d_level_5.1.exists()); + + fs_extra::file::write_all(&file1.0, "content1").unwrap(); + fs_extra::file::write_all(&file2.0, "content2").unwrap(); + fs_extra::file::write_all(&file3.0, "content3").unwrap(); + fs_extra::file::write_all(&file4.0, "content4").unwrap(); + fs_extra::file::write_all(&file5.0, "content5").unwrap(); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file3.0.exists()); + assert!(file4.0.exists()); + assert!(file5.0.exists()); + + assert!(!file1.1.exists()); + assert!(!file2.1.exists()); + assert!(!file3.1.exists()); + assert!(!file4.1.exists()); + assert!(!file5.1.exists()); + + let mut options = CopyOptions::new(); + options.depth = 1; + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let func_test = |process_info: TransitProcess| { + tx.send(process_info).unwrap(); + TransitProcessResult::ContinueOrAbort + }; + + let result = copy_with_progress(&d_level_1.0, &path_to, &options, func_test).unwrap(); + + assert_eq!(8, result); + + assert!(d_level_1.0.exists()); + assert!(d_level_2.0.exists()); + assert!(d_level_3.0.exists()); + assert!(d_level_4.0.exists()); + assert!(d_level_5.0.exists()); + + assert!(d_level_1.1.exists()); + assert!(d_level_2.1.exists()); + assert!(!d_level_3.1.exists()); + assert!(!d_level_4.1.exists()); + assert!(!d_level_5.1.exists()); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file3.0.exists()); + assert!(file4.0.exists()); + assert!(file5.0.exists()); + + assert!(file1.1.exists()); + assert!(!file2.1.exists()); + assert!(!file3.1.exists()); + assert!(!file4.1.exists()); + assert!(!file5.1.exists()); + assert!(files_eq(&file1.0, &file1.1)); + }) + .join(); + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } + + match rx.recv() { + Err(_) => panic!("Errors should not be!"), + _ => {} + } +} + +#[test] +fn it_copy_with_progress_using_four_levels() { + let test_dir = Path::new(TEST_FOLDER).join("it_copy_with_progress_using_four_levels"); + let path_to = test_dir.join("out"); + let d_level_1 = (test_dir.join("d_level_1"), path_to.join("d_level_1")); + let d_level_2 = (d_level_1.0.join("d_level_2"), d_level_1.1.join("d_level_2")); + let d_level_3 = (d_level_2.0.join("d_level_3"), d_level_2.1.join("d_level_3")); + let d_level_4 = (d_level_3.0.join("d_level_4"), d_level_3.1.join("d_level_4")); + let d_level_5 = (d_level_4.0.join("d_level_5"), d_level_4.1.join("d_level_5")); + + let file1 = (d_level_1.0.join("file1.txt"), d_level_1.1.join("file1.txt")); + let file2 = (d_level_2.0.join("file2.txt"), d_level_2.1.join("file2.txt")); + let file3 = (d_level_3.0.join("file3.txt"), d_level_3.1.join("file3.txt")); + let file4 = (d_level_4.0.join("file4.txt"), d_level_4.1.join("file4.txt")); + let file5 = (d_level_5.0.join("file5.txt"), d_level_5.1.join("file5.txt")); + + create_all(&d_level_1.0, true).unwrap(); + create_all(&d_level_2.0, true).unwrap(); + create_all(&d_level_3.0, true).unwrap(); + create_all(&d_level_4.0, true).unwrap(); + create_all(&d_level_5.0, true).unwrap(); + create_all(&path_to, true).unwrap(); + + assert!(path_to.exists()); + assert!(d_level_1.0.exists()); + assert!(d_level_2.0.exists()); + assert!(d_level_3.0.exists()); + assert!(d_level_4.0.exists()); + assert!(d_level_5.0.exists()); + + assert!(!d_level_1.1.exists()); + assert!(!d_level_2.1.exists()); + assert!(!d_level_3.1.exists()); + assert!(!d_level_4.1.exists()); + assert!(!d_level_5.1.exists()); + + fs_extra::file::write_all(&file1.0, "content1").unwrap(); + fs_extra::file::write_all(&file2.0, "content2").unwrap(); + fs_extra::file::write_all(&file3.0, "content3").unwrap(); + fs_extra::file::write_all(&file4.0, "content4").unwrap(); + fs_extra::file::write_all(&file5.0, "content5").unwrap(); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file3.0.exists()); + assert!(file4.0.exists()); + assert!(file5.0.exists()); + + assert!(!file1.1.exists()); + assert!(!file2.1.exists()); + assert!(!file3.1.exists()); + assert!(!file4.1.exists()); + assert!(!file5.1.exists()); + + let mut options = CopyOptions::new(); + options.depth = 4; + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let func_test = |process_info: TransitProcess| { + tx.send(process_info).unwrap(); + TransitProcessResult::ContinueOrAbort + }; + + let result = copy_with_progress(&d_level_1.0, &path_to, &options, func_test).unwrap(); + + assert_eq!(32, result); + + assert!(d_level_1.0.exists()); + assert!(d_level_2.0.exists()); + assert!(d_level_3.0.exists()); + assert!(d_level_4.0.exists()); + assert!(d_level_5.0.exists()); + + assert!(d_level_1.1.exists()); + assert!(d_level_2.1.exists()); + assert!(d_level_3.1.exists()); + assert!(d_level_4.1.exists()); + assert!(d_level_5.1.exists()); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file3.0.exists()); + assert!(file4.0.exists()); + assert!(file5.0.exists()); + + assert!(file1.1.exists()); + assert!(file2.1.exists()); + assert!(file3.1.exists()); + assert!(file4.1.exists()); + assert!(!file5.1.exists()); + assert!(files_eq(&file1.0, &file1.1)); + assert!(files_eq(&file2.0, &file2.1)); + assert!(files_eq(&file3.0, &file3.1)); + assert!(files_eq(&file4.0, &file4.1)); + }) + .join(); + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } + + match rx.recv() { + Err(_) => panic!("Errors should not be!"), + _ => {} + } +} +#[test] +fn it_copy_with_progress_content_only_option() { + let test_dir = Path::new(TEST_FOLDER).join("it_copy_with_progress_content_only_option"); + let path_to = test_dir.join("out"); + let d_level_1 = (test_dir.join("d_level_1"), path_to.clone()); + let d_level_2 = (d_level_1.0.join("d_level_2"), d_level_1.1.join("d_level_2")); + let d_level_3 = (d_level_2.0.join("d_level_3"), d_level_2.1.join("d_level_3")); + + let file1 = (d_level_1.0.join("file1.txt"), d_level_1.1.join("file1.txt")); + let file2 = (d_level_2.0.join("file2.txt"), d_level_2.1.join("file2.txt")); + let file3 = (d_level_3.0.join("file3.txt"), d_level_3.1.join("file3.txt")); + + create_all(&d_level_1.0, true).unwrap(); + create_all(&d_level_2.0, true).unwrap(); + create_all(&d_level_3.0, true).unwrap(); + create_all(&path_to, true).unwrap(); + + assert!(path_to.exists()); + assert!(d_level_1.0.exists()); + assert!(d_level_2.0.exists()); + assert!(d_level_3.0.exists()); + + assert!(!d_level_2.1.exists()); + assert!(!d_level_3.1.exists()); + + fs_extra::file::write_all(&file1.0, "content1").unwrap(); + fs_extra::file::write_all(&file2.0, "content2").unwrap(); + fs_extra::file::write_all(&file3.0, "content3").unwrap(); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file3.0.exists()); + + assert!(!file1.1.exists()); + assert!(!file2.1.exists()); + assert!(!file3.1.exists()); + + let mut options = CopyOptions::new(); + options.content_only = true; + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let func_test = |process_info: TransitProcess| { + tx.send(process_info).unwrap(); + TransitProcessResult::ContinueOrAbort + }; + + let result = copy_with_progress(&d_level_1.0, &path_to, &options, func_test).unwrap(); + + assert_eq!(24, result); + + assert!(d_level_1.0.exists()); + assert!(d_level_2.0.exists()); + assert!(d_level_3.0.exists()); + + assert!(d_level_1.1.exists()); + assert!(d_level_2.1.exists()); + assert!(d_level_3.1.exists()); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file3.0.exists()); + + assert!(file1.1.exists()); + assert!(file2.1.exists()); + assert!(file3.1.exists()); + assert!(files_eq(&file1.0, &file1.1)); + assert!(files_eq(&file2.0, &file2.1)); + assert!(files_eq(&file3.0, &file3.1)); + }) + .join(); + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } + + match rx.recv() { + Err(_) => panic!("Errors should not be!"), + _ => {} + } +} + +#[test] +fn it_copy_inside_work_target_dir_not_exist() { + let path_root = Path::new(TEST_FOLDER); + let root = path_root.join("it_copy_inside_work_target_dir_not_exist"); + let root_dir1 = root.join("dir1"); + let root_dir1_sub = root_dir1.join("sub"); + let root_dir2 = root.join("dir2"); + let file1 = root_dir1.join("file1.txt"); + let file2 = root_dir1_sub.join("file2.txt"); + + create_all(&root_dir1_sub, true).unwrap(); + fs_extra::file::write_all(&file1, "content1").unwrap(); + fs_extra::file::write_all(&file2, "content2").unwrap(); + + if root_dir2.exists() { + remove(&root_dir2).unwrap(); + } + + assert!(root_dir1.exists()); + assert!(root_dir1_sub.exists()); + assert!(!root_dir2.exists()); + assert!(file1.exists()); + assert!(file2.exists()); + + let mut options = CopyOptions::new(); + options.copy_inside = true; + let result = copy(&root_dir1, &root_dir2, &options).unwrap(); + + assert_eq!(16, result); + assert!(root_dir1.exists()); + assert!(root_dir1_sub.exists()); + assert!(root_dir2.exists()); + assert!(compare_dir_recursively(&root_dir1, &root_dir2)); +} + +#[test] +fn it_copy_inside_work_target_dir_exist_with_no_source_dir_named_sub_dir() { + let path_root = Path::new(TEST_FOLDER); + let root = + path_root.join("it_copy_inside_work_target_dir_exist_with_no_source_dir_named_sub_dir"); + let root_dir1 = root.join("dir1"); + let root_dir1_sub = root_dir1.join("sub"); + let root_dir2 = root.join("dir2"); + let root_dir2_dir1 = root_dir2.join("dir1"); + let root_dir2_dir3 = root_dir2.join("dir3"); + let file1 = root_dir1.join("file1.txt"); + let file2 = root_dir1_sub.join("file2.txt"); + let file3 = root_dir2_dir3.join("file3.txt"); + + create_all(&root_dir1_sub, true).unwrap(); + create_all(&root_dir2_dir3, true).unwrap(); + fs_extra::file::write_all(&file1, "content1").unwrap(); + fs_extra::file::write_all(&file2, "content2").unwrap(); + fs_extra::file::write_all(&file3, "content3").unwrap(); + + if root_dir2_dir1.exists() { + remove(&root_dir2_dir1).unwrap(); + } + + assert!(root_dir1.exists()); + assert!(root_dir1_sub.exists()); + assert!(root_dir2.exists()); + assert!(!root_dir2_dir1.exists()); + assert!(root_dir2_dir3.exists()); + assert!(file1.exists()); + assert!(file2.exists()); + assert!(file3.exists()); + + let mut options = CopyOptions::new(); + options.copy_inside = true; + let result = copy(&root_dir1, &root_dir2, &options).unwrap(); + + assert_eq!(16, result); + assert!(root_dir1.exists()); + assert!(root_dir1_sub.exists()); + assert!(root_dir2.exists()); + assert!(root_dir2_dir1.exists()); + assert!(root_dir2_dir3.exists()); + assert!(compare_dir(&root_dir1, &root_dir2)); +} + +#[test] +fn it_copy_inside_work_target_dir_exist_with_source_dir_exist() { + let path_root = Path::new(TEST_FOLDER); + let root = path_root.join("it_copy_inside_work_target_dir_exist_with_source_dir_exist"); + let root_dir1 = root.join("dir1"); + let root_dir1_sub = root_dir1.join("sub"); + let root_dir2 = root.join("dir2"); + let root_dir2_dir1 = root_dir2.join("dir1"); + let root_dir2_dir1_sub = root_dir2_dir1.join("sub"); + let root_dir2_dir3 = root_dir2.join("dir3"); + let file1 = root_dir1.join("file1.txt"); + let file2 = root_dir1_sub.join("file2.txt"); + let file3 = root_dir2_dir3.join("file3.txt"); + let old_file1 = root_dir2_dir1.join("file1.txt"); + let old_file2 = root_dir2_dir1_sub.join("file2.txt"); + + create_all(&root_dir1_sub, true).unwrap(); + create_all(&root_dir2_dir3, true).unwrap(); + create_all(&root_dir2_dir1, true).unwrap(); + create_all(&root_dir2_dir1_sub, true).unwrap(); + fs_extra::file::write_all(&file1, "content1").unwrap(); + fs_extra::file::write_all(&file2, "content2").unwrap(); + fs_extra::file::write_all(&file3, "content3").unwrap(); + fs_extra::file::write_all(&old_file1, "old_content1").unwrap(); + fs_extra::file::write_all(&old_file2, "old_content2").unwrap(); + + assert!(root_dir1.exists()); + assert!(root_dir1_sub.exists()); + assert!(root_dir2.exists()); + assert!(root_dir2_dir1.exists()); + assert!(root_dir2_dir1_sub.exists()); + assert!(root_dir2_dir3.exists()); + assert!(file1.exists()); + assert!(file2.exists()); + assert!(file3.exists()); + assert!(old_file1.exists()); + assert!(old_file2.exists()); + + let mut options = CopyOptions::new(); + options.copy_inside = true; + match copy(&root_dir1, &root_dir2, &options) { + Err(err) => match err.kind { + ErrorKind::AlreadyExists => { + assert_eq!(1, 1); + } + _ => { + panic!(format!("wrong error {}", err.to_string())); + } + }, + Ok(_) => { + panic!("should be error"); + } + } + options.overwrite = true; + + let result = copy(&root_dir1, &root_dir2, &options).unwrap(); + + assert_eq!(16, result); + assert!(root_dir1.exists()); + assert!(root_dir1_sub.exists()); + assert!(root_dir2.exists()); + assert!(root_dir2_dir1.exists()); + assert!(root_dir2_dir1_sub.exists()); + assert!(root_dir2_dir3.exists()); + assert!(compare_dir(&root_dir1, &root_dir2)); +} + +// The compare_dir method assumes that the folder `path_to` must have a sub folder named the last component of the `path_from`. +// In order to compare two folders with different name but share the same structure, rewrite a new compare method to do that! +fn compare_dir_recursively(path_from: P, path_to: Q) -> bool +where + P: AsRef, + Q: AsRef, +{ + let path_to = path_to.as_ref().to_path_buf(); + + for entry in read_dir(&path_from).unwrap() { + let entry = entry.unwrap(); + let path = entry.path(); + if path.is_dir() { + match path.components().last() { + None => panic!("Invalid folder from"), + Some(dir_name) => { + let mut target_dir = path_to.to_path_buf(); + target_dir.push(dir_name.as_os_str()); + if !compare_dir_recursively(path.clone(), &target_dir) { + return false; + } + } + } + } else { + let mut target_file = path_to.to_path_buf(); + match path.file_name() { + None => panic!("No file name"), + Some(file_name) => { + target_file.push(file_name); + if !target_file.exists() { + return false; + } else if !files_eq(&path, target_file.clone()) { + return false; + } + } + } + } + } + + true +} + +#[test] +fn it_move_work() { + let mut path_from = PathBuf::from(TEST_FOLDER); + let test_name = "sub"; + path_from.push("it_move_work"); + let mut path_to = path_from.clone(); + path_to.push("out"); + path_from.push(&test_name); + + create_all(&path_from, true).unwrap(); + assert!(path_from.exists()); + create_all(&path_to, true).unwrap(); + assert!(path_to.exists()); + + let mut file1_path = path_from.clone(); + file1_path.push("test1.txt"); + let content1 = "content1"; + fs_extra::file::write_all(&file1_path, &content1).unwrap(); + assert!(file1_path.exists()); + + let mut sub_dir_path = path_from.clone(); + sub_dir_path.push("sub"); + create(&sub_dir_path, true).unwrap(); + let mut file2_path = sub_dir_path.clone(); + file2_path.push("test2.txt"); + let content2 = "content2"; + fs_extra::file::write_all(&file2_path, &content2).unwrap(); + assert!(file2_path.exists()); + + let options = CopyOptions::new(); + let result = move_dir(&path_from, &path_to, &options).unwrap(); + + assert_eq!(16, result); + assert!(path_to.exists()); + assert!(!path_from.exists()); +} + +#[test] +fn it_move_not_folder() { + let mut path_from = PathBuf::from(TEST_FOLDER); + path_from.push("it_move_not_folder"); + let mut path_to = path_from.clone(); + path_to.push("out"); + path_from.push("sub"); + + create_all(&path_from, true).unwrap(); + assert!(path_from.exists()); + create_all(&path_to, true).unwrap(); + assert!(path_to.exists()); + + let options = CopyOptions::new(); + path_from.push("test.txt"); + fs_extra::file::write_all(&path_from, "test").unwrap(); + + match move_dir(&path_from, &path_to, &options) { + Err(err) => match err.kind { + ErrorKind::InvalidFolder => { + let wrong_path = format!( + "Path \"{}\" is not a directory or you don't have \ + access!", + path_from.to_str().unwrap() + ); + assert_eq!(wrong_path, err.to_string()); + } + _ => { + panic!("wrong error"); + } + }, + Ok(_) => { + panic!("should be error"); + } + } +} + +#[test] +fn it_move_source_not_exist() { + let mut path_from = PathBuf::from(TEST_FOLDER); + path_from.push("it_move_source_not_exist"); + let mut path_to = path_from.clone(); + path_to.push("out"); + path_from.push("sub"); + + assert!(!path_from.exists()); + create_all(&path_to, true).unwrap(); + assert!(path_to.exists()); + + let options = CopyOptions::new(); + match move_dir(&path_from, &path_to, &options) { + Err(err) => match err.kind { + ErrorKind::NotFound => { + let wrong_path = format!("Path \"{}\" does not exist", path_from.to_str().unwrap()); + assert_eq!(wrong_path, err.to_string()); + } + _ => { + panic!(format!("wrong error {}", err.to_string())); + } + }, + Ok(_) => { + panic!("should be error"); + } + } +} + +#[test] +fn it_move_exist_overwrite() { + let mut path_from = PathBuf::from(TEST_FOLDER); + let test_name = "sub"; + path_from.push("it_move_exist_overwrite"); + let mut path_to = path_from.clone(); + path_to.push("out"); + path_from.push(&test_name); + let same_file = "test.txt"; + + create_all(&path_from, true).unwrap(); + assert!(path_from.exists()); + create_all(&path_to, true).unwrap(); + assert!(path_to.exists()); + + let mut file1_path = path_from.clone(); + file1_path.push(same_file); + let content1 = "content1"; + fs_extra::file::write_all(&file1_path, &content1).unwrap(); + assert!(file1_path.exists()); + + let mut sub_dir_path = path_from.clone(); + sub_dir_path.push("sub"); + create(&sub_dir_path, true).unwrap(); + let mut file2_path = sub_dir_path.clone(); + file2_path.push("test2.txt"); + let content2 = "content2"; + fs_extra::file::write_all(&file2_path, &content2).unwrap(); + assert!(file2_path.exists()); + + let mut exist_path = path_to.clone(); + exist_path.push(&test_name); + create(&exist_path, true).unwrap(); + assert!(exist_path.exists()); + exist_path.push(same_file); + let exist_content = "exist content"; + assert_ne!(exist_content, content1); + fs_extra::file::write_all(&exist_path, exist_content).unwrap(); + assert!(exist_path.exists()); + + let mut options = CopyOptions::new(); + options.overwrite = true; + move_dir(&path_from, &path_to, &options).unwrap(); + + assert!(exist_path.exists()); + assert!(path_to.exists()); + assert!(!path_from.exists()); +} + +#[test] +fn it_move_exist_not_overwrite() { + let test_name = "sub"; + let mut path_from = PathBuf::from(TEST_FOLDER); + path_from.push("it_move_exist_not_overwrite"); + let mut path_to = path_from.clone(); + path_to.push("out"); + path_from.push(test_name); + let same_file = "test.txt"; + + create_all(&path_from, true).unwrap(); + assert!(path_from.exists()); + create_all(&path_to, true).unwrap(); + assert!(path_to.exists()); + + let mut file1_path = path_from.clone(); + file1_path.push(same_file); + let content1 = "content1"; + fs_extra::file::write_all(&file1_path, &content1).unwrap(); + assert!(file1_path.exists()); + + let mut exist_path = path_to.clone(); + exist_path.push(&test_name); + create(&exist_path, true).unwrap(); + assert!(exist_path.exists()); + exist_path.push(same_file); + let exist_content = "exist content"; + assert_ne!(exist_content, content1); + fs_extra::file::write_all(&exist_path, exist_content).unwrap(); + assert!(exist_path.exists()); + + let options = CopyOptions::new(); + match move_dir(&path_from, &path_to, &options) { + Err(err) => match err.kind { + ErrorKind::AlreadyExists => { + let wrong_path = format!("Path \"{}\" exists", exist_path.to_str().unwrap()); + assert_eq!(wrong_path, err.to_string()); + } + _ => { + panic!(format!("wrong error {}", err.to_string())); + } + }, + Ok(_) => { + panic!("should be error"); + } + } +} + +#[test] +fn it_move_exist_skip_exist() { + let mut path_from = PathBuf::from(TEST_FOLDER); + let test_name = "sub"; + path_from.push("it_move_exist_skip_exist"); + let mut path_to = path_from.clone(); + path_to.push("out"); + path_from.push(&test_name); + let same_file = "test.txt"; + + create_all(&path_from, true).unwrap(); + assert!(path_from.exists()); + create_all(&path_to, true).unwrap(); + assert!(path_to.exists()); + + let mut file1_path = path_from.clone(); + file1_path.push(same_file); + let content1 = "content1"; + fs_extra::file::write_all(&file1_path, &content1).unwrap(); + assert!(file1_path.exists()); + + let mut sub_dir_path = path_from.clone(); + sub_dir_path.push("sub"); + create(&sub_dir_path, true).unwrap(); + let mut file2_path = sub_dir_path.clone(); + file2_path.push("test2.txt"); + let content2 = "content2"; + fs_extra::file::write_all(&file2_path, &content2).unwrap(); + assert!(file2_path.exists()); + + let mut exist_path = path_to.clone(); + exist_path.push(&test_name); + create(&exist_path, true).unwrap(); + assert!(exist_path.exists()); + exist_path.push(same_file); + let exist_content = "exist content"; + assert_ne!(exist_content, content1); + fs_extra::file::write_all(&exist_path, exist_content).unwrap(); + assert!(exist_path.exists()); + + let mut options = CopyOptions::new(); + options.skip_exist = true; + move_dir(&path_from, &path_to, &options).unwrap(); + + assert!(exist_path.exists()); + assert_eq!( + fs_extra::file::read_to_string(exist_path).unwrap(), + exist_content + ); + + assert!(path_to.exists()); +} + +#[test] +fn it_move_exist_overwrite_and_skip_exist() { + let mut path_from = PathBuf::from(TEST_FOLDER); + let test_name = "sub"; + path_from.push("it_move_exist_overwrite_and_skip_exist"); + let mut path_to = path_from.clone(); + path_to.push("out"); + path_from.push(&test_name); + let same_file = "test.txt"; + + create_all(&path_from, true).unwrap(); + assert!(path_from.exists()); + create_all(&path_to, true).unwrap(); + assert!(path_to.exists()); + + let mut file1_path = path_from.clone(); + file1_path.push(same_file); + let content1 = "content1"; + fs_extra::file::write_all(&file1_path, &content1).unwrap(); + assert!(file1_path.exists()); + + let mut sub_dir_path = path_from.clone(); + sub_dir_path.push("sub"); + create(&sub_dir_path, true).unwrap(); + let mut file2_path = sub_dir_path.clone(); + file2_path.push("test2.txt"); + let content2 = "content2"; + fs_extra::file::write_all(&file2_path, &content2).unwrap(); + assert!(file2_path.exists()); + + let mut exist_path = path_to.clone(); + exist_path.push(&test_name); + create(&exist_path, true).unwrap(); + assert!(exist_path.exists()); + exist_path.push(same_file); + let exist_content = "exist content"; + assert_ne!(exist_content, content1); + fs_extra::file::write_all(&exist_path, exist_content).unwrap(); + assert!(exist_path.exists()); + + let mut options = CopyOptions::new(); + options.overwrite = true; + options.skip_exist = true; + move_dir(&path_from, &path_to, &options).unwrap(); + + assert!(exist_path.exists()); + assert!(path_to.exists()); + assert!(!path_from.exists()); +} + +#[test] +fn it_move_inside_work_target_dir_not_exist() { + let path_root = Path::new(TEST_FOLDER); + let root = path_root.join("it_move_inside_work_target_dir_not_exist"); + let root_dir1 = root.join("dir1"); + let root_dir1_sub = root_dir1.join("sub"); + let root_dir2 = root.join("dir2"); + let file1 = root_dir1.join("file1.txt"); + let file2 = root_dir1_sub.join("file2.txt"); + + create_all(&root_dir1_sub, true).unwrap(); + fs_extra::file::write_all(&file1, "content1").unwrap(); + fs_extra::file::write_all(&file2, "content2").unwrap(); + + if root_dir2.exists() { + remove(&root_dir2).unwrap(); + } + + assert!(root_dir1.exists()); + assert!(root_dir1_sub.exists()); + assert!(!root_dir2.exists()); + assert!(file1.exists()); + assert!(file2.exists()); + + let mut options = CopyOptions::new(); + options.copy_inside = true; + let result = move_dir(&root_dir1, &root_dir2, &options).unwrap(); + + assert_eq!(16, result); + assert!(!root_dir1.exists()); + let root_dir2_sub = root_dir2.join("sub"); + let root_dir2_file1 = root_dir2.join("file1.txt"); + let root_dir2_sub_file2 = root_dir2_sub.join("file2.txt"); + assert!(root_dir2.exists()); + assert!(root_dir2_sub.exists()); + assert!(root_dir2_file1.exists()); + assert!(root_dir2_sub_file2.exists()); +} + +#[test] +fn it_move_inside_work_target_dir_exist_with_no_source_dir_named_sub_dir() { + let path_root = Path::new(TEST_FOLDER); + let root = + path_root.join("it_move_inside_work_target_dir_exist_with_no_source_dir_named_sub_dir"); + let root_dir1 = root.join("dir1"); + let root_dir1_sub = root_dir1.join("sub"); + let root_dir2 = root.join("dir2"); + let root_dir2_dir1 = root_dir2.join("dir1"); + let root_dir2_dir3 = root_dir2.join("dir3"); + let file1 = root_dir1.join("file1.txt"); + let file2 = root_dir1_sub.join("file2.txt"); + let file3 = root_dir2_dir3.join("file3.txt"); + + create_all(&root_dir1_sub, true).unwrap(); + create_all(&root_dir2_dir3, true).unwrap(); + fs_extra::file::write_all(&file1, "content1").unwrap(); + fs_extra::file::write_all(&file2, "content2").unwrap(); + fs_extra::file::write_all(&file3, "content3").unwrap(); + + if root_dir2_dir1.exists() { + remove(&root_dir2_dir1).unwrap(); + } + + assert!(root_dir1.exists()); + assert!(root_dir1_sub.exists()); + assert!(root_dir2.exists()); + assert!(!root_dir2_dir1.exists()); + assert!(root_dir2_dir3.exists()); + assert!(file1.exists()); + assert!(file2.exists()); + assert!(file3.exists()); + + let mut options = CopyOptions::new(); + options.copy_inside = true; + let result = move_dir(&root_dir1, &root_dir2, &options).unwrap(); + + assert_eq!(16, result); + assert!(!root_dir1.exists()); + assert!(root_dir2.exists()); + assert!(root_dir2_dir1.exists()); + assert!(root_dir2_dir3.exists()); + let root_dir2_dir1_file1 = root_dir2_dir1.join("file1.txt"); + let root_dir2_dir1_sub = root_dir2_dir1.join("sub"); + let root_dir2_dir1_sub_file2 = root_dir2_dir1_sub.join("file2.txt"); + let root_dir2_dir3_file3 = root_dir2_dir3.join("file3.txt"); + assert!(root_dir2_dir1_file1.exists()); + assert!(root_dir2_dir1_sub.exists()); + assert!(root_dir2_dir1_sub_file2.exists()); + assert!(root_dir2_dir3_file3.exists()); +} + +#[test] +fn it_move_inside_work_target_dir_exist_with_source_dir_exist() { + let path_root = Path::new(TEST_FOLDER); + let root = path_root.join("it_move_inside_work_target_dir_exist_with_source_dir_exist"); + let root_dir1 = root.join("dir1"); + let root_dir1_sub = root_dir1.join("sub"); + let root_dir2 = root.join("dir2"); + let root_dir2_dir1 = root_dir2.join("dir1"); + let root_dir2_dir1_sub = root_dir2_dir1.join("sub"); + let root_dir2_dir3 = root_dir2.join("dir3"); + let file1 = root_dir1.join("file1.txt"); + let file2 = root_dir1_sub.join("file2.txt"); + let file3 = root_dir2_dir3.join("file3.txt"); + let old_file1 = root_dir2_dir1.join("file1.txt"); + let old_file2 = root_dir2_dir1_sub.join("file2.txt"); + + create_all(&root_dir1_sub, true).unwrap(); + create_all(&root_dir2_dir3, true).unwrap(); + create_all(&root_dir2_dir1, true).unwrap(); + create_all(&root_dir2_dir1_sub, true).unwrap(); + fs_extra::file::write_all(&file1, "content1").unwrap(); + fs_extra::file::write_all(&file2, "content2").unwrap(); + fs_extra::file::write_all(&file3, "content3").unwrap(); + fs_extra::file::write_all(&old_file1, "old_content1").unwrap(); + fs_extra::file::write_all(&old_file2, "old_content2").unwrap(); + + assert!(root_dir1.exists()); + assert!(root_dir1_sub.exists()); + assert!(root_dir2.exists()); + assert!(root_dir2_dir1.exists()); + assert!(root_dir2_dir1_sub.exists()); + assert!(root_dir2_dir3.exists()); + assert!(file1.exists()); + assert!(file2.exists()); + assert!(file3.exists()); + assert!(old_file1.exists()); + assert!(old_file2.exists()); + + let mut options = CopyOptions::new(); + options.copy_inside = true; + match copy(&root_dir1, &root_dir2, &options) { + Err(err) => match err.kind { + ErrorKind::AlreadyExists => { + assert_eq!(1, 1); + } + _ => { + panic!(format!("wrong error {}", err.to_string())); + } + }, + Ok(_) => { + panic!("should be error"); + } + } + options.overwrite = true; + let result = move_dir(&root_dir1, &root_dir2, &options).unwrap(); + + assert_eq!(16, result); + assert!(!root_dir1.exists()); + assert!(root_dir2.exists()); + assert!(root_dir2_dir1.exists()); + assert!(root_dir2_dir1_sub.exists()); + assert!(root_dir2_dir3.exists()); + let root_dir2_dir1_file1 = root_dir2_dir1.join("file1.txt"); + let root_dir2_dir1_sub_file2 = root_dir2_dir1_sub.join("file2.txt"); + let root_dir2_dir3_file3 = root_dir2_dir3.join("file3.txt"); + assert!(root_dir2_dir1_file1.exists()); + assert!(root_dir2_dir1_sub_file2.exists()); + assert!(root_dir2_dir3_file3.exists()); +} +#[test] +fn it_move_content_only_option() { + let test_dir = Path::new(TEST_FOLDER).join("it_move_content_only_option"); + let path_to = test_dir.join("out"); + let d_level_1 = (test_dir.join("d_level_1"), path_to.clone()); + let d_level_2 = (d_level_1.0.join("d_level_2"), d_level_1.1.join("d_level_2")); + let d_level_3 = (d_level_2.0.join("d_level_3"), d_level_2.1.join("d_level_3")); + + let file1 = (d_level_1.0.join("file1.txt"), d_level_1.1.join("file1.txt")); + let file2 = (d_level_2.0.join("file2.txt"), d_level_2.1.join("file2.txt")); + let file3 = (d_level_3.0.join("file3.txt"), d_level_3.1.join("file3.txt")); + + create_all(&d_level_1.0, true).unwrap(); + create_all(&d_level_2.0, true).unwrap(); + create_all(&d_level_3.0, true).unwrap(); + create_all(&path_to, true).unwrap(); + + assert!(path_to.exists()); + assert!(d_level_1.0.exists()); + assert!(d_level_2.0.exists()); + assert!(d_level_3.0.exists()); + + assert!(!d_level_2.1.exists()); + assert!(!d_level_3.1.exists()); + + fs_extra::file::write_all(&file1.0, "content1").unwrap(); + fs_extra::file::write_all(&file2.0, "content2").unwrap(); + fs_extra::file::write_all(&file3.0, "content3").unwrap(); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file3.0.exists()); + + assert!(!file1.1.exists()); + assert!(!file2.1.exists()); + assert!(!file3.1.exists()); + + let mut options = CopyOptions::new(); + options.content_only = true; + let result = move_dir(&d_level_1.0, path_to, &options).unwrap(); + + assert_eq!(24, result); + + assert!(!d_level_1.0.exists()); + assert!(!d_level_2.0.exists()); + assert!(!d_level_3.0.exists()); + + assert!(d_level_1.1.exists()); + assert!(d_level_2.1.exists()); + assert!(d_level_3.1.exists()); + + assert!(!file1.0.exists()); + assert!(!file2.0.exists()); + assert!(!file3.0.exists()); + + assert!(file1.1.exists()); + assert!(file2.1.exists()); + assert!(file3.1.exists()); +} +#[test] +fn it_move_progress_work() { + let mut path_from = PathBuf::from(TEST_FOLDER); + let test_name = "sub"; + path_from.push("it_move_progress_work"); + let mut path_to = path_from.clone(); + path_to.push("out"); + path_from.push(&test_name); + + create_all(&path_from, true).unwrap(); + assert!(path_from.exists()); + create_all(&path_to, true).unwrap(); + assert!(path_to.exists()); + + let mut file1_path = path_from.clone(); + file1_path.push("test1.txt"); + let content1 = "content"; + fs_extra::file::write_all(&file1_path, &content1).unwrap(); + assert!(file1_path.exists()); + + let mut sub_dir_path = path_from.clone(); + sub_dir_path.push("sub"); + create(&sub_dir_path, true).unwrap(); + let mut file2_path = sub_dir_path.clone(); + file2_path.push("test2.txt"); + let content2 = "content2"; + fs_extra::file::write_all(&file2_path, &content2).unwrap(); + assert!(file2_path.exists()); + + let mut options = CopyOptions::new(); + + options.buffer_size = 1; + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let func_test = |process_info: TransitProcess| { + tx.send(process_info).unwrap(); + TransitProcessResult::ContinueOrAbort + }; + let result = move_dir_with_progress(&path_from, &path_to, &options, func_test).unwrap(); + + assert_eq!(15, result); + assert!(path_to.exists()); + assert!(!path_from.exists()); + }) + .join(); + + loop { + match rx.try_recv() { + Ok(process_info) => { + if process_info.file_name == "test2.txt" { + assert_eq!(8, process_info.file_total_bytes); + assert_eq!(get_dir_size() * 2 + 15, process_info.total_bytes); + } else if process_info.file_name == "test1.txt" { + assert_eq!(7, process_info.file_total_bytes); + assert_eq!(get_dir_size() * 2 + 15, process_info.total_bytes); + } else { + panic!("Unknow file name!"); + } + } + Err(TryRecvError::Disconnected) => { + break; + } + Err(TryRecvError::Empty) => {} + } + } + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } +} + +#[test] +fn it_move_with_progress_not_folder() { + let mut path_from = PathBuf::from(TEST_FOLDER); + path_from.push("it_move_with_progress_not_folder"); + let mut path_to = path_from.clone(); + path_to.push("out"); + path_from.push("sub"); + + create_all(&path_from, true).unwrap(); + assert!(path_from.exists()); + create_all(&path_to, true).unwrap(); + assert!(path_to.exists()); + + let options = CopyOptions::new(); + path_from.push("test.txt"); + fs_extra::file::write_all(&path_from, "test").unwrap(); + let func_test = |process_info: TransitProcess| { + match process_info.state { + TransitState::NoAccess => {} + _ => panic!("Error not should be!"), + }; + TransitProcessResult::ContinueOrAbort + }; + + match move_dir_with_progress(&path_from, &path_to, &options, func_test) { + Err(err) => match err.kind { + ErrorKind::InvalidFolder => { + let wrong_path = format!( + "Path \"{}\" is not a directory!", + path_from.to_str().unwrap() + ); + assert_eq!(wrong_path, err.to_string()); + } + _ => { + panic!("wrong error"); + } + }, + Ok(_) => { + panic!("should be error"); + } + } +} + +#[test] +fn it_move_with_progress_work_dif_buf_size() { + let mut path_from = PathBuf::from(TEST_FOLDER); + let test_name = "sub"; + path_from.push("it_move_with_progress_work_dif_buf_size"); + let mut path_to = path_from.clone(); + path_to.push("out"); + path_from.push(&test_name); + + create_all(&path_from, true).unwrap(); + assert!(path_from.exists()); + create_all(&path_to, true).unwrap(); + assert!(path_to.exists()); + + let mut file1_path = path_from.clone(); + file1_path.push("test1.txt"); + let content1 = "content1"; + fs_extra::file::write_all(&file1_path, &content1).unwrap(); + assert!(file1_path.exists()); + + let mut sub_dir_path = path_from.clone(); + sub_dir_path.push("sub"); + create(&sub_dir_path, true).unwrap(); + let mut file2_path = sub_dir_path.clone(); + file2_path.push("test2.txt"); + let content2 = "content2"; + fs_extra::file::write_all(&file2_path, &content2).unwrap(); + assert!(file2_path.exists()); + + let mut options = CopyOptions::new(); + + options.buffer_size = 1; + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let func_test = |process_info: TransitProcess| { + tx.send(process_info).unwrap(); + TransitProcessResult::ContinueOrAbort + }; + + let result = move_dir_with_progress(&path_from, &path_to, &options, func_test).unwrap(); + + assert_eq!(16, result); + assert!(path_to.exists()); + assert!(!path_from.exists()); + + create_all(&path_from, true).unwrap(); + assert!(path_from.exists()); + let mut file1_path = path_from.clone(); + file1_path.push("test1.txt"); + let content1 = "content1"; + fs_extra::file::write_all(&file1_path, &content1).unwrap(); + assert!(file1_path.exists()); + + let mut sub_dir_path = path_from.clone(); + sub_dir_path.push("sub"); + create(&sub_dir_path, true).unwrap(); + let mut file2_path = sub_dir_path.clone(); + file2_path.push("test2.txt"); + let content2 = "content2"; + fs_extra::file::write_all(&file2_path, &content2).unwrap(); + assert!(file2_path.exists()); + + let mut options = CopyOptions::new(); + options.buffer_size = 2; + options.overwrite = true; + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let func_test = |process_info: TransitProcess| { + tx.send(process_info).unwrap(); + TransitProcessResult::ContinueOrAbort + }; + let result = move_dir_with_progress(&path_from, &path_to, &options, func_test).unwrap(); + + assert_eq!(16, result); + assert!(path_to.exists()); + assert!(!path_from.exists()); + }) + .join(); + for i in 1..5 { + let process_info: TransitProcess = rx.recv().unwrap(); + assert_eq!(i * 2, process_info.file_bytes_copied); + assert_eq!(i * 2, process_info.copied_bytes); + assert_eq!(8, process_info.file_total_bytes); + assert_eq!(get_dir_size() * 2 + 16, process_info.total_bytes); + } + for i in 1..5 { + let process_info: TransitProcess = rx.recv().unwrap(); + assert_eq!(i * 2 + 8, process_info.copied_bytes); + assert_eq!(i * 2, process_info.file_bytes_copied); + assert_eq!(8, process_info.file_total_bytes); + assert_eq!(get_dir_size() * 2 + 16, process_info.total_bytes); + } + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } + }) + .join(); + + for i in 1..9 { + let process_info: TransitProcess = rx.recv().unwrap(); + assert_eq!(i, process_info.file_bytes_copied); + assert_eq!(i, process_info.copied_bytes); + assert_eq!(8, process_info.file_total_bytes); + assert_eq!(get_dir_size() * 2 + 16, process_info.total_bytes); + } + for i in 1..9 { + let process_info: TransitProcess = rx.recv().unwrap(); + assert_eq!(i + 8, process_info.copied_bytes); + assert_eq!(i, process_info.file_bytes_copied); + assert_eq!(8, process_info.file_total_bytes); + assert_eq!(get_dir_size() * 2 + 16, process_info.total_bytes); + } + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } +} +#[test] +fn it_move_with_progress_source_not_exist() { + let mut path_from = PathBuf::from(TEST_FOLDER); + path_from.push("it_move_with_progress_source_not_exist"); + let mut path_to = path_from.clone(); + path_to.push("out"); + path_from.push("sub"); + + assert!(!path_from.exists()); + create_all(&path_to, true).unwrap(); + assert!(path_to.exists()); + + let options = CopyOptions::new(); + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let func_test = |process_info: TransitProcess| { + tx.send(process_info).unwrap(); + TransitProcessResult::ContinueOrAbort + }; + + match move_dir_with_progress(&path_from, &path_to, &options, func_test) { + Err(err) => match err.kind { + ErrorKind::NotFound => { + let wrong_path = format!( + "Path \"{}\" does not exist or you don't \ + have access!", + path_from.to_str().unwrap() + ); + assert_eq!(wrong_path, err.to_string()); + } + _ => { + panic!(format!("wrong error {}", err.to_string())); + } + }, + Ok(_) => { + panic!("should be error"); + } + } + }) + .join(); + match result { + Ok(_) => {} + Err(err) => panic!(err), + } + + match rx.recv() { + Err(_) => {} + _ => panic!("should be error"), + } +} + +#[test] +fn it_move_with_progress_exist_overwrite() { + let mut path_from = PathBuf::from(TEST_FOLDER); + let test_name = "sub"; + path_from.push("it_move_with_progress_exist_overwrite"); + let mut path_to = path_from.clone(); + path_to.push("out"); + path_from.push(&test_name); + + create_all(&path_from, true).unwrap(); + assert!(path_from.exists()); + create_all(&path_to, true).unwrap(); + assert!(path_to.exists()); + + let mut file1_path = path_from.clone(); + file1_path.push("test1.txt"); + let content1 = "content"; + fs_extra::file::write_all(&file1_path, &content1).unwrap(); + assert!(file1_path.exists()); + + let mut sub_dir_path = path_from.clone(); + sub_dir_path.push("sub"); + create(&sub_dir_path, true).unwrap(); + let mut file2_path = sub_dir_path.clone(); + file2_path.push("test2.txt"); + let content2 = "content2"; + fs_extra::file::write_all(&file2_path, &content2).unwrap(); + assert!(file2_path.exists()); + + let mut options = CopyOptions::new(); + copy(&path_from, &path_to, &options).unwrap(); + fs_extra::file::write_all(&file2_path, "another conntent").unwrap(); + + options.buffer_size = 1; + options.overwrite = true; + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let func_test = |process_info: TransitProcess| { + tx.send(process_info).unwrap(); + TransitProcessResult::ContinueOrAbort + }; + + let result = move_dir_with_progress(&path_from, &path_to, &options, func_test).unwrap(); + + assert_eq!(23, result); + assert!(path_to.exists()); + assert!(!path_from.exists()); + }) + .join(); + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } + rx.recv().unwrap(); +} + +#[test] +fn it_move_with_progress_exist_not_overwrite() { + let mut path_from = PathBuf::from(TEST_FOLDER); + let test_name = "sub"; + path_from.push("it_move_with_progress_exist_not_overwrite"); + let mut path_to = path_from.clone(); + path_to.push("out"); + path_from.push(&test_name); + + create_all(&path_from, true).unwrap(); + assert!(path_from.exists()); + create_all(&path_to, true).unwrap(); + assert!(path_to.exists()); + + let mut file1_path = path_from.clone(); + file1_path.push("test1.txt"); + let content1 = "content"; + fs_extra::file::write_all(&file1_path, &content1).unwrap(); + assert!(file1_path.exists()); + + let mut sub_dir_path = path_from.clone(); + sub_dir_path.push("sub"); + create(&sub_dir_path, true).unwrap(); + let mut file2_path = sub_dir_path.clone(); + file2_path.push("test2.txt"); + let content2 = "content2"; + fs_extra::file::write_all(&file2_path, &content2).unwrap(); + assert!(file2_path.exists()); + + let mut options = CopyOptions::new(); + copy(&path_from, &path_to, &options).unwrap(); + + options.buffer_size = 1; + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let func_test = |process_info: TransitProcess| { + tx.send(process_info).unwrap(); + TransitProcessResult::ContinueOrAbort + }; + + let result = move_dir_with_progress(&path_from, &path_to, &options, func_test); + match result { + Ok(_) => panic!("Should be error!"), + Err(err) => match err.kind { + ErrorKind::AlreadyExists => {} + _ => panic!("Wrong wrror"), + }, + } + }) + .join(); + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } + + match rx.recv() { + Err(_) => { + panic!("Error not should be!"); + } + _ => {} + } +} + +#[test] +fn it_move_with_progress_exist_skip_exist() { + let mut path_from = PathBuf::from(TEST_FOLDER); + let test_name = "sub"; + path_from.push("it_move_with_progress_exist_skip_exist"); + let mut path_to = path_from.clone(); + path_to.push("out"); + path_from.push(&test_name); + + create_all(&path_from, true).unwrap(); + assert!(path_from.exists()); + create_all(&path_to, true).unwrap(); + assert!(path_to.exists()); + + let mut file1_path = path_from.clone(); + file1_path.push("test1.txt"); + let content1 = "content"; + fs_extra::file::write_all(&file1_path, &content1).unwrap(); + assert!(file1_path.exists()); + + let mut sub_dir_path = path_from.clone(); + sub_dir_path.push("sub"); + create(&sub_dir_path, true).unwrap(); + let mut file2_path = sub_dir_path.clone(); + file2_path.push("test2.txt"); + let content2 = "content2"; + fs_extra::file::write_all(&file2_path, &content2).unwrap(); + assert!(file2_path.exists()); + + let mut options = CopyOptions::new(); + copy(&path_from, &path_to, &options).unwrap(); + + fs_extra::file::write_all(&file2_path, "another conntent").unwrap(); + options.buffer_size = 1; + options.skip_exist = true; + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let func_test = |process_info: TransitProcess| { + tx.send(process_info).unwrap(); + TransitProcessResult::ContinueOrAbort + }; + + let result = move_dir_with_progress(&path_from, &path_to, &options, func_test).unwrap(); + + assert_eq!(0, result); + assert!(path_from.exists()); + assert!(path_to.exists()); + }) + .join(); + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } + + match rx.recv() { + Err(_) => {} + _ => panic!("should be error"), + } +} + +#[test] +fn it_move_with_progress_exist_overwrite_and_skip_exist() { + let mut path_from = PathBuf::from(TEST_FOLDER); + let test_name = "sub"; + path_from.push("it_move_with_progress_exist_overwrite_and_skip_exist"); + let mut path_to = path_from.clone(); + path_to.push("out"); + path_from.push(&test_name); + + create_all(&path_from, true).unwrap(); + assert!(path_from.exists()); + create_all(&path_to, true).unwrap(); + assert!(path_to.exists()); + + let mut file1_path = path_from.clone(); + file1_path.push("test1.txt"); + let content1 = "content"; + fs_extra::file::write_all(&file1_path, &content1).unwrap(); + assert!(file1_path.exists()); + + let mut sub_dir_path = path_from.clone(); + sub_dir_path.push("sub"); + create(&sub_dir_path, true).unwrap(); + let mut file2_path = sub_dir_path.clone(); + file2_path.push("test2.txt"); + let content2 = "content2"; + fs_extra::file::write_all(&file2_path, &content2).unwrap(); + assert!(file2_path.exists()); + + let mut options = CopyOptions::new(); + copy(&path_from, &path_to, &options).unwrap(); + fs_extra::file::write_all(&file2_path, "another conntent").unwrap(); + + options.buffer_size = 1; + options.overwrite = true; + options.skip_exist = true; + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let func_test = |process_info: TransitProcess| { + tx.send(process_info).unwrap(); + TransitProcessResult::ContinueOrAbort + }; + + let result = move_dir_with_progress(&path_from, &path_to, &options, func_test).unwrap(); + + assert_eq!(23, result); + assert!(path_to.exists()); + assert!(!path_from.exists()); + }) + .join(); + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } + rx.recv().unwrap(); +} + +#[test] +fn it_get_folder_size() { + let mut path = PathBuf::from(TEST_FOLDER); + path.push("it_get_folder_size"); + path.push("dir"); + + create_all(&path, true).unwrap(); + assert!(path.exists()); + + let mut file1 = path.clone(); + file1.push("test1.txt"); + fs_extra::file::write_all(&file1, &"A".repeat(100)).unwrap(); + assert!(file1.exists()); + + let mut sub_dir_path = path.clone(); + sub_dir_path.push("sub"); + create(&sub_dir_path, true).unwrap(); + + let mut file2 = sub_dir_path.clone(); + file2.push("test2.txt"); + fs_extra::file::write_all(&file2, &"B".repeat(300)).unwrap(); + assert!(file2.exists()); + + let symlink_file = sub_dir_path.join("symlink_file.txt"); + + // Rust stdlib APIs for creating a symlinked file only exist for Unix and Windows. + #[cfg(any(unix, windows))] + { + // Only passing the filename since we want this to be a relative symlink. + create_file_symlink("test2.txt", &symlink_file).unwrap(); + assert!(symlink_file.exists()); + } + + // Total size comprises of: + // - 100 bytes for the standard file "test1.txt" + // - 300 bytes for the standard file "test2.txt" + // - (On supported platforms) 1 x symlink whose whose size varies by filesystem, so is dynamically calculated. + let mut expected_size = 100 + 300; + + if symlink_file.exists() { + // `fs::symlink_metadata` does not follow symlinks, so this is the size of the symlink itself, not its target. + expected_size += fs::symlink_metadata(&symlink_file).unwrap().len(); + } + + let result = get_size(&path).unwrap(); + + assert_eq!(expected_size, result); +} + +#[test] +fn it_get_file_size() { + let mut path = PathBuf::from(TEST_FOLDER); + path.push("it_get_file_size"); + + create_all(&path, true).unwrap(); + assert!(path.exists()); + + let mut file = path.clone(); + file.push("test1.txt"); + fs_extra::file::write_all(&file, "content").unwrap(); + assert!(file.exists()); + + let result = get_size(&path).unwrap(); + + assert_eq!(7, result); +} + +#[test] +fn it_get_size_not_found() { + let mut path = PathBuf::from(TEST_FOLDER); + path.push("it_get_size_not_found"); + + assert!(!path.exists()); + + match get_size(&path) { + Ok(_) => panic!("Should be a error!"), + Err(err) => match err.kind { + ErrorKind::NotFound => {} + _ => panic!("Wrong error!"), + }, + }; +} + +#[test] +fn it_get_dir_content() { + let mut path = PathBuf::from(TEST_FOLDER); + path.push("it_get_dir_content"); + path.push("dir"); + + create_all(&path, true).unwrap(); + assert!(path.exists()); + + let mut file1 = path.clone(); + file1.push("test1.txt"); + fs_extra::file::write_all(&file1, "content1").unwrap(); + assert!(file1.exists()); + + let mut sub_dir_path = path.clone(); + sub_dir_path.push("sub"); + create(&sub_dir_path, true).unwrap(); + let mut file2 = sub_dir_path.clone(); + file2.push("test2.txt"); + fs_extra::file::write_all(&file2, "content2").unwrap(); + assert!(file2.exists()); + + let result = get_dir_content(&path).unwrap(); + + assert_eq!(get_dir_size() * 2 + 16, result.dir_size); + assert_eq!(2, result.files.len()); + assert_eq!(2, result.directories.len()); + + let dir1 = file1.parent().unwrap().to_str().unwrap().to_string(); + let dir2 = file2.parent().unwrap().to_str().unwrap().to_string(); + let file1 = file1.to_str().unwrap().to_string(); + let file2 = file2.to_str().unwrap().to_string(); + + let mut files_correct = true; + for file in result.files { + if file != file1 && file != file2 { + files_correct = false; + } + } + assert!(files_correct); + + let mut directories_correct = true; + for dir in result.directories { + if dir != dir1 && dir != dir2 { + directories_correct = false; + } + } + assert!(directories_correct); +} + +#[test] +fn it_get_dir_content_many_levels() { + let test_dir = Path::new(TEST_FOLDER).join("it_get_dir_content_many_levels"); + let d_level_1 = test_dir.join("d_level_1"); + let d_level_2 = d_level_1.join("d_level_2"); + let d_level_3 = d_level_2.join("d_level_3"); + let d_level_4 = d_level_3.join("d_level_4"); + let d_level_5 = d_level_4.join("d_level_5"); + + let file1 = d_level_1.join("file1.txt"); + let file2 = d_level_2.join("file2.txt"); + let file3 = d_level_3.join("file3.txt"); + let file4 = d_level_4.join("file4.txt"); + let file5 = d_level_5.join("file5.txt"); + + create_all(&d_level_1, true).unwrap(); + create_all(&d_level_2, true).unwrap(); + create_all(&d_level_3, true).unwrap(); + create_all(&d_level_4, true).unwrap(); + create_all(&d_level_5, true).unwrap(); + + assert!(&d_level_1.exists()); + assert!(&d_level_2.exists()); + assert!(&d_level_3.exists()); + assert!(&d_level_4.exists()); + assert!(&d_level_5.exists()); + + fs_extra::file::write_all(&file1, "content1").unwrap(); + fs_extra::file::write_all(&file2, "content2").unwrap(); + fs_extra::file::write_all(&file3, "content3").unwrap(); + fs_extra::file::write_all(&file4, "content4").unwrap(); + fs_extra::file::write_all(&file5, "content5").unwrap(); + + let mut options = DirOptions::new(); + let result = get_dir_content2(&d_level_1, &options).unwrap(); + + assert_eq!(get_dir_size() * 5 + 40, result.dir_size); + assert_eq!(5, result.files.len()); + assert_eq!(5, result.directories.len()); + + let mut directories = Vec::new(); + directories.push(file1.parent().unwrap().to_str().unwrap().to_string()); + directories.push(file2.parent().unwrap().to_str().unwrap().to_string()); + directories.push(file3.parent().unwrap().to_str().unwrap().to_string()); + directories.push(file4.parent().unwrap().to_str().unwrap().to_string()); + directories.push(file5.parent().unwrap().to_str().unwrap().to_string()); + + let mut files = Vec::new(); + files.push(file1.to_str().unwrap().to_string()); + files.push(file2.to_str().unwrap().to_string()); + files.push(file3.to_str().unwrap().to_string()); + files.push(file4.to_str().unwrap().to_string()); + files.push(file5.to_str().unwrap().to_string()); + + let mut files_correct = true; + for file in result.files { + if !files.contains(&file) { + files_correct = false; + } + } + assert!(files_correct); + + let mut directories_correct = true; + for dir in result.directories { + if !directories.contains(&dir) { + directories_correct = false; + } + } + assert!(directories_correct); + + // first level + options.depth = 1; + let result = get_dir_content2(&d_level_1, &options).unwrap(); + + assert_eq!(get_dir_size() * 2 + 8, result.dir_size); + assert_eq!(1, result.files.len()); + assert_eq!(2, result.directories.len()); + files_correct = true; + for file in &result.files { + if !files.contains(&file) { + files_correct = false; + } + } + assert!(files_correct); + assert!(result.files.contains(&file1.to_str().unwrap().to_string())); + + directories_correct = true; + for dir in &result.directories { + if !directories.contains(&dir) { + directories_correct = false; + } + } + assert!(directories_correct); + assert!(result + .directories + .contains(&file1.parent().unwrap().to_str().unwrap().to_string(),)); + assert!(result + .directories + .contains(&file2.parent().unwrap().to_str().unwrap().to_string(),)); + + // fourth level + options.depth = 4; + let result = get_dir_content2(&d_level_1, &options).unwrap(); + + assert_eq!(get_dir_size() * 5 + 32, result.dir_size); + assert_eq!(4, result.files.len()); + assert_eq!(5, result.directories.len()); + files_correct = true; + for file in &result.files { + if !files.contains(&file) { + files_correct = false; + } + } + assert!(files_correct); + assert!(result.files.contains(&file1.to_str().unwrap().to_string())); + assert!(result.files.contains(&file2.to_str().unwrap().to_string())); + assert!(result.files.contains(&file3.to_str().unwrap().to_string())); + assert!(result.files.contains(&file4.to_str().unwrap().to_string())); + + directories_correct = true; + for dir in &result.directories { + if !directories.contains(&dir) { + directories_correct = false; + } + } + assert!(directories_correct); + assert!(result + .directories + .contains(&file1.parent().unwrap().to_str().unwrap().to_string(),)); + assert!(result + .directories + .contains(&file2.parent().unwrap().to_str().unwrap().to_string(),)); + assert!(result + .directories + .contains(&file3.parent().unwrap().to_str().unwrap().to_string(),)); + assert!(result + .directories + .contains(&file4.parent().unwrap().to_str().unwrap().to_string(),)); + assert!(result + .directories + .contains(&file5.parent().unwrap().to_str().unwrap().to_string(),)); +} + +#[test] +fn it_get_dir_content_path_file() { + let mut path = PathBuf::from(TEST_FOLDER); + path.push("it_get_dir_content_path_file"); + + create_all(&path, true).unwrap(); + assert!(path.exists()); + + let mut file = path.clone(); + file.push("test1.txt"); + fs_extra::file::write_all(&file, "content1").unwrap(); + assert!(file.exists()); + + let result = get_dir_content(&file).unwrap(); + + assert_eq!(8, result.dir_size); + assert_eq!(1, result.files.len()); + assert_eq!(0, result.directories.len()); + assert_eq!(file.to_str().unwrap().to_string(), result.files[0]); +} + +#[test] +fn it_get_dir_content_not_found() { + let mut path = PathBuf::from(TEST_FOLDER); + path.push("it_get_dir_content_not_found"); + + assert!(!path.exists()); + + match get_dir_content(&path) { + Ok(_) => panic!("Should be a error!"), + Err(err) => match err.kind { + ErrorKind::NotFound => {} + _ => panic!("Wrong error!"), + }, + } +} + +#[test] +fn it_details_item_dir() { + let test_dir = Path::new(TEST_FOLDER).join("it_details_item_dir"); + create_all(&test_dir, true).unwrap(); + assert!(test_dir.exists()); + let mut config = HashSet::new(); + config.insert(DirEntryAttr::Name); + config.insert(DirEntryAttr::Ext); + config.insert(DirEntryAttr::FullName); + config.insert(DirEntryAttr::Path); + config.insert(DirEntryAttr::DosPath); + config.insert(DirEntryAttr::Size); + config.insert(DirEntryAttr::IsDir); + config.insert(DirEntryAttr::IsFile); + config.insert(DirEntryAttr::Modified); + config.insert(DirEntryAttr::Accessed); + let item = get_details_entry(test_dir, &config).unwrap(); + assert_eq!(10, item.len()); + + let mut fields = 0; + if let Some(name) = item.get(&DirEntryAttr::Name) { + if let &DirEntryValue::String(ref name) = name { + assert_eq!("it_details_item_dir", name); + fields += 1; + } + } + if let Some(ext) = item.get(&DirEntryAttr::Ext) { + if let &DirEntryValue::String(ref ext) = ext { + assert_eq!("", ext); + fields += 1; + } + } + if let Some(fname) = item.get(&DirEntryAttr::FullName) { + if let &DirEntryValue::String(ref fname) = fname { + assert_eq!("it_details_item_dir", fname); + fields += 1; + } + } + if let Some(path) = item.get(&DirEntryAttr::Path) { + if let &DirEntryValue::String(ref path) = path { + if !path.is_empty() { + fields += 1; + } + } + } + if let Some(path) = item.get(&DirEntryAttr::DosPath) { + if let &DirEntryValue::String(ref path) = path { + if !path.is_empty() { + fields += 1; + } + } + } + if let Some(size) = item.get(&DirEntryAttr::Size) { + if let &DirEntryValue::U64(size) = size { + assert_eq!(0, size); + fields += 1; + } + } + if let Some(is_dir) = item.get(&DirEntryAttr::IsDir) { + if let &DirEntryValue::Boolean(is_dir) = is_dir { + assert_eq!(true, is_dir); + fields += 1; + } + } + + if let Some(is_file) = item.get(&DirEntryAttr::IsFile) { + if let &DirEntryValue::Boolean(is_file) = is_file { + assert_eq!(false, is_file); + fields += 1; + } + } + + if let Some(modified) = item.get(&DirEntryAttr::Modified) { + if let &DirEntryValue::SystemTime(modified) = modified { + if modified.elapsed().unwrap().as_secs() == 0 { + fields += 1; + } + } + } + if let Some(accessed) = item.get(&DirEntryAttr::Accessed) { + if let &DirEntryValue::SystemTime(accessed) = accessed { + if accessed.elapsed().unwrap().as_secs() == 0 { + fields += 1; + } + } + } + + assert_eq!(10, fields); +} + +#[test] +fn it_details_file_item() { + let test_dir = Path::new(TEST_FOLDER).join("it_details_file_item"); + create_all(&test_dir, true).unwrap(); + let file = test_dir.join("file.txt"); + fs_extra::file::write_all(&file, "content").unwrap(); + assert!(file.exists()); + let mut config = HashSet::new(); + config.insert(DirEntryAttr::Name); + config.insert(DirEntryAttr::Ext); + config.insert(DirEntryAttr::FullName); + config.insert(DirEntryAttr::Path); + config.insert(DirEntryAttr::DosPath); + config.insert(DirEntryAttr::Size); + config.insert(DirEntryAttr::FileSize); + config.insert(DirEntryAttr::IsDir); + config.insert(DirEntryAttr::IsFile); + config.insert(DirEntryAttr::Modified); + config.insert(DirEntryAttr::Accessed); + let item = get_details_entry(file, &config).unwrap(); + assert_eq!(11, item.len()); + + let mut fields = 0; + if let Some(name) = item.get(&DirEntryAttr::Name) { + if let &DirEntryValue::String(ref name) = name { + assert_eq!("file", name); + fields += 1; + } + } + if let Some(ext) = item.get(&DirEntryAttr::Ext) { + if let &DirEntryValue::String(ref ext) = ext { + assert_eq!("txt", ext); + fields += 1; + } + } + if let Some(fname) = item.get(&DirEntryAttr::FullName) { + if let &DirEntryValue::String(ref fname) = fname { + assert_eq!("file.txt", fname); + fields += 1; + } + } + if let Some(path) = item.get(&DirEntryAttr::Path) { + if let &DirEntryValue::String(ref path) = path { + if !path.is_empty() { + fields += 1; + } + } + } + if let Some(path) = item.get(&DirEntryAttr::DosPath) { + if let &DirEntryValue::String(ref path) = path { + if !path.is_empty() { + fields += 1; + } + } + } + if let Some(size) = item.get(&DirEntryAttr::Size) { + if let &DirEntryValue::U64(size) = size { + assert_eq!(7, size); + fields += 1; + } + } + if let Some(size) = item.get(&DirEntryAttr::FileSize) { + if let &DirEntryValue::U64(size) = size { + assert_eq!(7, size); + fields += 1; + } + } + if let Some(is_dir) = item.get(&DirEntryAttr::IsDir) { + if let &DirEntryValue::Boolean(is_dir) = is_dir { + assert_eq!(false, is_dir); + fields += 1; + } + } + + if let Some(is_file) = item.get(&DirEntryAttr::IsFile) { + if let &DirEntryValue::Boolean(is_file) = is_file { + assert_eq!(true, is_file); + fields += 1; + } + } + + if let Some(modified) = item.get(&DirEntryAttr::Modified) { + if let &DirEntryValue::SystemTime(modified) = modified { + if modified.elapsed().unwrap().as_secs() == 0 { + fields += 1; + } + } + } + if let Some(accessed) = item.get(&DirEntryAttr::Accessed) { + if let &DirEntryValue::SystemTime(accessed) = accessed { + if accessed.elapsed().unwrap().as_secs() == 0 { + fields += 1; + } + } + } + + assert_eq!(11, fields); +} + +#[test] +fn it_details_item_dir_short() { + let test_dir = Path::new(TEST_FOLDER).join("it_details_item_dir_short"); + create_all(&test_dir, true).unwrap(); + assert!(test_dir.exists()); + let mut config = HashSet::new(); + config.insert(DirEntryAttr::Name); + config.insert(DirEntryAttr::Size); + let item = get_details_entry(test_dir, &config).unwrap(); + assert_eq!(2, item.len()); + + if let Some(name) = item.get(&DirEntryAttr::Name) { + if let &DirEntryValue::String(ref name) = name { + assert_eq!("it_details_item_dir_short", name); + } + } + if let Some(size) = item.get(&DirEntryAttr::Size) { + if let &DirEntryValue::U64(size) = size { + assert_eq!(0, size); + } + } +} + +#[test] +fn it_details_item_file_short() { + let test_dir = Path::new(TEST_FOLDER).join("it_details_item_short"); + create_all(&test_dir, true).unwrap(); + let file = test_dir.join("file.txt"); + fs_extra::file::write_all(&file, "content").unwrap(); + assert!(file.exists()); + let mut config = HashSet::new(); + config.insert(DirEntryAttr::Name); + config.insert(DirEntryAttr::Size); + let item = get_details_entry(file, &config).unwrap(); + assert_eq!(2, item.len()); + + if let Some(name) = item.get(&DirEntryAttr::Name) { + if let &DirEntryValue::String(ref name) = name { + assert_eq!("file", name); + } + } + if let Some(size) = item.get(&DirEntryAttr::Size) { + if let &DirEntryValue::U64(size) = size { + assert_eq!(7, size); + } + } +} + +#[test] +fn it_ls() { + let test_dir = Path::new(TEST_FOLDER).join("it_ls"); + create_all(&test_dir, true).unwrap(); + let file1 = test_dir.join("file1.txt"); + let file2 = test_dir.join("file2.txt"); + fs_extra::file::write_all(&file1, "content").unwrap(); + fs_extra::file::write_all(&file2, "content").unwrap(); + assert!(file1.exists()); + assert!(file2.exists()); + let mut config = HashSet::new(); + config.insert(DirEntryAttr::Name); + config.insert(DirEntryAttr::Size); + config.insert(DirEntryAttr::IsDir); + config.insert(DirEntryAttr::BaseInfo); + let ls_result = ls(&test_dir, &config).unwrap(); + assert_eq!(2, ls_result.items.len()); + assert_eq!(3, ls_result.base.len()); + + if let Some(name) = ls_result.base.get(&DirEntryAttr::Name) { + if let &DirEntryValue::String(ref name) = name { + assert_eq!("it_ls", name); + } + } + if let Some(size) = ls_result.base.get(&DirEntryAttr::Size) { + if let &DirEntryValue::U64(size) = size { + assert_eq!(14, size); + } + } + if let Some(is_dir) = ls_result.base.get(&DirEntryAttr::IsDir) { + if let &DirEntryValue::Boolean(is_dir) = is_dir { + assert_eq!(true, is_dir); + } + } + for item in ls_result.items { + if let Some(name) = item.get(&DirEntryAttr::Name) { + if let &DirEntryValue::String(ref name) = name { + assert_eq!(String::from("file"), name[..4]); + } + } + if let Some(size) = item.get(&DirEntryAttr::Size) { + if let &DirEntryValue::U64(size) = size { + assert_eq!(7, size); + } + } + if let Some(is_dir) = item.get(&DirEntryAttr::IsDir) { + if let &DirEntryValue::Boolean(is_dir) = is_dir { + assert_eq!(false, is_dir); + } + } + } +} + +#[test] +fn it_copy_with_progress_exist_user_decide_overwrite() { + let test_dir = Path::new(TEST_FOLDER).join("it_copy_with_progress_exist_user_decide_overwrite"); + let out = test_dir.join("out"); + let dir = (test_dir.join("dir"), out.join("dir")); + let file1 = (dir.0.join("file1.txt"), dir.1.join("file1.txt")); + let file2 = (dir.0.join("file2.txt"), dir.1.join("file2.txt")); + + create_all(&dir.0, true).unwrap(); + create_all(&dir.1, true).unwrap(); + + assert!(&dir.0.exists()); + assert!(&dir.1.exists()); + + fs_extra::file::write_all(&file1.0, "content1").unwrap(); + fs_extra::file::write_all(&file2.0, "content2").unwrap(); + + fs_extra::file::write_all(&file1.1, "old content7").unwrap(); + fs_extra::file::write_all(&file2.1, "old content3").unwrap(); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file1.1.exists()); + assert!(file2.1.exists()); + + let mut options = CopyOptions::new(); + assert!(!compare_dir(&dir.0, &out)); + options.buffer_size = 1; + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let mut count_exist_files = 0; + let result: u64; + { + let func_test = |process_info: TransitProcess| { + let result: TransitProcessResult; + match process_info.state { + TransitState::Exists => { + count_exist_files += 1; + result = TransitProcessResult::Overwrite; + tx.send(process_info).unwrap(); + } + _ => result = TransitProcessResult::Abort, + }; + result + }; + result = copy_with_progress(&dir.0, &out, &options, func_test).unwrap(); + } + assert_eq!(2, count_exist_files); + + assert_eq!(16, result); + assert!(dir.0.exists()); + assert!(dir.1.exists()); + assert!(compare_dir(&dir.0, &out)); + }) + .join(); + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } + rx.try_recv().unwrap(); +} + +#[test] +fn it_copy_with_progress_exist_user_decide_overwrite_all() { + let test_dir = + Path::new(TEST_FOLDER).join("it_copy_with_progress_exist_user_decide_overwrite_all"); + let out = test_dir.join("out"); + let dir = (test_dir.join("dir"), out.join("dir")); + let file1 = (dir.0.join("file1.txt"), dir.1.join("file1.txt")); + let file2 = (dir.0.join("file2.txt"), dir.1.join("file2.txt")); + + create_all(&dir.0, true).unwrap(); + create_all(&dir.1, true).unwrap(); + + assert!(&dir.0.exists()); + assert!(&dir.1.exists()); + + fs_extra::file::write_all(&file1.0, "content1").unwrap(); + fs_extra::file::write_all(&file2.0, "content2").unwrap(); + + fs_extra::file::write_all(&file1.1, "old content7").unwrap(); + fs_extra::file::write_all(&file2.1, "old content3").unwrap(); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file1.1.exists()); + assert!(file2.1.exists()); + + let mut options = CopyOptions::new(); + assert!(!compare_dir(&dir.0, &out)); + options.buffer_size = 1; + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let mut count_exist_files = 0; + let result: u64; + { + let func_test = |process_info: TransitProcess| { + let result: TransitProcessResult; + match process_info.state { + TransitState::Exists => { + count_exist_files += 1; + result = TransitProcessResult::OverwriteAll; + tx.send(process_info).unwrap(); + } + _ => result = TransitProcessResult::Abort, + }; + result + }; + result = copy_with_progress(&dir.0, &out, &options, func_test).unwrap(); + } + assert_eq!(1, count_exist_files); + + assert_eq!(16, result); + assert!(dir.0.exists()); + assert!(dir.1.exists()); + assert!(compare_dir(&dir.0, &out)); + }) + .join(); + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } + rx.try_recv().unwrap(); +} + +#[test] +fn it_copy_with_progress_exist_user_decide_skip() { + let test_dir = Path::new(TEST_FOLDER).join("it_copy_with_progress_exist_user_decide_skip"); + let out = test_dir.join("out"); + let dir = (test_dir.join("dir"), out.join("dir")); + let file1 = (dir.0.join("file1.txt"), dir.1.join("file1.txt")); + let file2 = (dir.0.join("file2.txt"), dir.1.join("file2.txt")); + + create_all(&dir.0, true).unwrap(); + create_all(&dir.1, true).unwrap(); + + assert!(&dir.0.exists()); + assert!(&dir.1.exists()); + + fs_extra::file::write_all(&file1.0, "content1").unwrap(); + fs_extra::file::write_all(&file2.0, "content2").unwrap(); + + fs_extra::file::write_all(&file1.1, "old content7").unwrap(); + fs_extra::file::write_all(&file2.1, "old content3").unwrap(); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file1.1.exists()); + assert!(file2.1.exists()); + + let mut options = CopyOptions::new(); + assert!(!compare_dir(&dir.0, &out)); + options.buffer_size = 1; + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let mut count_exist_files = 0; + let result: u64; + { + let func_test = |process_info: TransitProcess| { + let result: TransitProcessResult; + match process_info.state { + TransitState::Exists => { + count_exist_files += 1; + result = TransitProcessResult::Skip; + tx.send(process_info).unwrap(); + } + _ => result = TransitProcessResult::Abort, + }; + result + }; + result = copy_with_progress(&dir.0, &out, &options, func_test).unwrap(); + } + assert_eq!(2, count_exist_files); + + assert_eq!(0, result); + assert!(dir.0.exists()); + assert!(dir.1.exists()); + assert!(!compare_dir(&dir.0, &out)); + }) + .join(); + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } + rx.try_recv().unwrap(); +} + +#[test] +fn it_copy_with_progress_exist_user_decide_skip_all() { + let test_dir = Path::new(TEST_FOLDER).join("it_copy_with_progress_exist_user_decide_skip_all"); + let out = test_dir.join("out"); + let dir = (test_dir.join("dir"), out.join("dir")); + let file1 = (dir.0.join("file1.txt"), dir.1.join("file1.txt")); + let file2 = (dir.0.join("file2.txt"), dir.1.join("file2.txt")); + + create_all(&dir.0, true).unwrap(); + create_all(&dir.1, true).unwrap(); + + assert!(&dir.0.exists()); + assert!(&dir.1.exists()); + + fs_extra::file::write_all(&file1.0, "content1").unwrap(); + fs_extra::file::write_all(&file2.0, "content2").unwrap(); + + fs_extra::file::write_all(&file1.1, "old content7").unwrap(); + fs_extra::file::write_all(&file2.1, "old content3").unwrap(); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file1.1.exists()); + assert!(file2.1.exists()); + + let mut options = CopyOptions::new(); + assert!(!compare_dir(&dir.0, &out)); + options.buffer_size = 1; + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let mut count_exist_files = 0; + let result: u64; + { + let func_test = |process_info: TransitProcess| { + let result: TransitProcessResult; + match process_info.state { + TransitState::Exists => { + count_exist_files += 1; + result = TransitProcessResult::SkipAll; + tx.send(process_info).unwrap(); + } + _ => result = TransitProcessResult::Abort, + }; + result + }; + result = copy_with_progress(&dir.0, &out, &options, func_test).unwrap(); + } + assert_eq!(1, count_exist_files); + + assert_eq!(0, result); + assert!(dir.0.exists()); + assert!(dir.1.exists()); + assert!(!compare_dir(&dir.0, &out)); + }) + .join(); + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } + rx.try_recv().unwrap(); +} + +#[test] +fn it_copy_with_progress_exist_user_decide_retry() { + let test_dir = Path::new(TEST_FOLDER).join("it_copy_with_progress_exist_user_decide_retry"); + let out = test_dir.join("out"); + let dir = (test_dir.join("dir"), out.join("dir")); + let file1 = (dir.0.join("file1.txt"), dir.1.join("file1.txt")); + let file2 = (dir.0.join("file2.txt"), dir.1.join("file2.txt")); + + create_all(&dir.0, true).unwrap(); + create_all(&dir.1, true).unwrap(); + + assert!(&dir.0.exists()); + assert!(&dir.1.exists()); + + fs_extra::file::write_all(&file1.0, "content1").unwrap(); + fs_extra::file::write_all(&file2.0, "content2").unwrap(); + + fs_extra::file::write_all(&file1.1, "old content7").unwrap(); + fs_extra::file::write_all(&file2.1, "old content3").unwrap(); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file1.1.exists()); + assert!(file2.1.exists()); + + let mut options = CopyOptions::new(); + assert!(!compare_dir(&dir.0, &out)); + options.buffer_size = 1; + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let mut count_exist_files = 0; + let result: u64; + { + let func_test = |process_info: TransitProcess| { + let result: TransitProcessResult; + match process_info.state { + TransitState::Exists => { + if count_exist_files == 3 || count_exist_files == 6 { + result = TransitProcessResult::Skip; + } else { + result = TransitProcessResult::Retry; + } + count_exist_files += 1; + tx.send(process_info).unwrap(); + } + _ => result = TransitProcessResult::Abort, + }; + result + }; + result = copy_with_progress(&dir.0, &out, &options, func_test).unwrap(); + } + assert_eq!(7, count_exist_files); + + assert_eq!(0, result); + assert!(dir.0.exists()); + assert!(dir.1.exists()); + assert!(!compare_dir(&dir.0, &out)); + }) + .join(); + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } + rx.try_recv().unwrap(); +} + +#[test] +fn it_copy_with_progress_inside_work_target_dir_not_exist() { + let path_root = Path::new(TEST_FOLDER); + let root = path_root.join("it_copy_with_progress_inside_work_target_dir_not_exist"); + let root_dir1 = root.join("dir1"); + let root_dir1_sub = root_dir1.join("sub"); + let root_dir2 = root.join("dir2"); + let file1 = root_dir1.join("file1.txt"); + let file2 = root_dir1_sub.join("file2.txt"); + + create_all(&root_dir1_sub, true).unwrap(); + fs_extra::file::write_all(&file1, "content").unwrap(); + fs_extra::file::write_all(&file2, "content2").unwrap(); + + if root_dir2.exists() { + remove(&root_dir2).unwrap(); + } + + assert!(root_dir1.exists()); + assert!(root_dir1_sub.exists()); + assert!(!root_dir2.exists()); + assert!(file1.exists()); + assert!(file2.exists()); + + let mut options = CopyOptions::new(); + options.copy_inside = true; + + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let func_test = |process_info: TransitProcess| { + tx.send(process_info).unwrap(); + TransitProcessResult::ContinueOrAbort + }; + let result = copy_with_progress(&root_dir1, &root_dir2, &options, func_test).unwrap(); + + assert_eq!(15, result); + assert!(root_dir1.exists()); + assert!(root_dir1_sub.exists()); + assert!(root_dir2.exists()); + assert!(compare_dir_recursively(&root_dir1, &root_dir2)); + }) + .join(); + + loop { + match rx.try_recv() { + Ok(process_info) => { + if process_info.file_name == "file2.txt" { + assert_eq!(8, process_info.file_total_bytes); + assert_eq!(get_dir_size() * 2 + 15, process_info.total_bytes); + } else if process_info.file_name == "file1.txt" { + assert_eq!(7, process_info.file_total_bytes); + assert_eq!(get_dir_size() * 2 + 15, process_info.total_bytes); + } else { + panic!("Unknow file name!"); + } + } + Err(TryRecvError::Disconnected) => { + break; + } + Err(TryRecvError::Empty) => {} + } + } + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } +} + +#[test] +fn it_copy_with_progress_inside_work_target_dir_exist_with_no_source_dir_named_sub_dir() { + let path_root = Path::new(TEST_FOLDER); + let root = path_root.join( + "it_copy_with_progress_inside_work_target_dir_exist_with_no_source_dir_named_sub_dir", + ); + let root_dir1 = root.join("dir1"); + let root_dir1_sub = root_dir1.join("sub"); + let root_dir2 = root.join("dir2"); + let root_dir2_dir1 = root_dir2.join("dir1"); + let root_dir2_dir3 = root_dir2.join("dir3"); + let file1 = root_dir1.join("file1.txt"); + let file2 = root_dir1_sub.join("file2.txt"); + let file3 = root_dir2_dir3.join("file3.txt"); + + create_all(&root_dir1_sub, true).unwrap(); + create_all(&root_dir2_dir3, true).unwrap(); + fs_extra::file::write_all(&file1, "content1").unwrap(); + fs_extra::file::write_all(&file2, "content22").unwrap(); + fs_extra::file::write_all(&file3, "content333").unwrap(); + + if root_dir2_dir1.exists() { + remove(&root_dir2_dir1).unwrap(); + } + + assert!(root_dir1.exists()); + assert!(root_dir1_sub.exists()); + assert!(root_dir2.exists()); + assert!(!root_dir2_dir1.exists()); + assert!(root_dir2_dir3.exists()); + assert!(file1.exists()); + assert!(file2.exists()); + assert!(file3.exists()); + + let mut options = CopyOptions::new(); + options.copy_inside = true; + + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let func_test = |process_info: TransitProcess| { + tx.send(process_info).unwrap(); + TransitProcessResult::ContinueOrAbort + }; + let result = copy_with_progress(&root_dir1, &root_dir2, &options, func_test).unwrap(); + + assert_eq!(17, result); + assert!(root_dir1.exists()); + assert!(root_dir1_sub.exists()); + assert!(root_dir2.exists()); + assert!(root_dir2_dir1.exists()); + assert!(root_dir2_dir3.exists()); + assert!(compare_dir(&root_dir1, &root_dir2)); + }) + .join(); + + loop { + match rx.try_recv() { + Ok(process_info) => { + if process_info.file_name == "file2.txt" { + assert_eq!(9, process_info.file_total_bytes); + assert_eq!(get_dir_size() * 2 + 17, process_info.total_bytes); + } else if process_info.file_name == "file1.txt" { + assert_eq!(8, process_info.file_total_bytes); + assert_eq!(get_dir_size() * 2 + 17, process_info.total_bytes); + } else { + panic!("Unknow file name!"); + } + } + Err(TryRecvError::Disconnected) => { + break; + } + Err(TryRecvError::Empty) => {} + } + } + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } +} + +#[test] +fn it_copy_with_progress_inside_no_overwrite_work_target_dir_exist_with_source_dir_exist() { + let path_root = Path::new(TEST_FOLDER); + let root = path_root.join( + "it_copy_with_progress_inside_no_overwrite_work_target_dir_exist_with_source_dir_exist", + ); + let root_dir1 = root.join("dir1"); + let root_dir1_sub = root_dir1.join("sub"); + let root_dir2 = root.join("dir2"); + let root_dir2_dir1 = root_dir2.join("dir1"); + let root_dir2_dir1_sub = root_dir2_dir1.join("sub"); + let root_dir2_dir3 = root_dir2.join("dir3"); + let file1 = root_dir1.join("file1.txt"); + let file2 = root_dir1_sub.join("file2.txt"); + let file3 = root_dir2_dir3.join("file3.txt"); + let old_file1 = root_dir2_dir1.join("file1.txt"); + let old_file2 = root_dir2_dir1_sub.join("file2.txt"); + + create_all(&root_dir1_sub, true).unwrap(); + create_all(&root_dir2_dir3, true).unwrap(); + create_all(&root_dir2_dir1, true).unwrap(); + create_all(&root_dir2_dir1_sub, true).unwrap(); + fs_extra::file::write_all(&file1, "content1").unwrap(); + fs_extra::file::write_all(&file2, "content22").unwrap(); + fs_extra::file::write_all(&file3, "content333").unwrap(); + fs_extra::file::write_all(&old_file1, "old_content1").unwrap(); + fs_extra::file::write_all(&old_file2, "old_content22").unwrap(); + + assert!(root_dir1.exists()); + assert!(root_dir1_sub.exists()); + assert!(root_dir2.exists()); + assert!(root_dir2_dir1.exists()); + assert!(root_dir2_dir1_sub.exists()); + assert!(root_dir2_dir3.exists()); + assert!(file1.exists()); + assert!(file2.exists()); + assert!(file3.exists()); + assert!(old_file1.exists()); + assert!(old_file2.exists()); + + let mut options = CopyOptions::new(); + options.copy_inside = true; + + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let func_test = |process_info: TransitProcess| { + tx.send(process_info).unwrap(); + TransitProcessResult::Skip + }; + let result = copy_with_progress(&root_dir1, &root_dir2, &options, func_test).unwrap(); + + assert_eq!(0, result); + assert!(root_dir1.exists()); + assert!(root_dir1_sub.exists()); + assert!(root_dir2.exists()); + assert!(root_dir2_dir1.exists()); + assert!(root_dir2_dir1_sub.exists()); + assert!(root_dir2_dir3.exists()); + assert!(!files_eq(file1, old_file1)); + assert!(!files_eq(file2, old_file2)); + }) + .join(); + + loop { + match rx.try_recv() { + Ok(process_info) => { + if process_info.file_name == "file2.txt" { + assert_eq!(9, process_info.file_total_bytes); + assert_eq!(get_dir_size() * 2 + 17, process_info.total_bytes); + } else if process_info.file_name == "file1.txt" { + assert_eq!(8, process_info.file_total_bytes); + assert_eq!(get_dir_size() * 2 + 17, process_info.total_bytes); + } else { + panic!("Unknow file name!"); + } + } + Err(TryRecvError::Disconnected) => { + break; + } + Err(TryRecvError::Empty) => {} + } + } + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } +} + +#[test] +fn it_copy_with_progress_inside_overwrite_work_target_dir_exist_with_source_dir_exist() { + let path_root = Path::new(TEST_FOLDER); + let root = path_root + .join("it_copy_with_progress_inside_overwrite_work_target_dir_exist_with_source_dir_exist"); + let root_dir1 = root.join("dir1"); + let root_dir1_sub = root_dir1.join("sub"); + let root_dir2 = root.join("dir2"); + let root_dir2_dir1 = root_dir2.join("dir1"); + let root_dir2_dir1_sub = root_dir2_dir1.join("sub"); + let root_dir2_dir3 = root_dir2.join("dir3"); + let file1 = root_dir1.join("file1.txt"); + let file2 = root_dir1_sub.join("file2.txt"); + let file3 = root_dir2_dir3.join("file3.txt"); + let old_file1 = root_dir2_dir1.join("file1.txt"); + let old_file2 = root_dir2_dir1_sub.join("file2.txt"); + + create_all(&root_dir1_sub, true).unwrap(); + create_all(&root_dir2_dir3, true).unwrap(); + create_all(&root_dir2_dir1, true).unwrap(); + create_all(&root_dir2_dir1_sub, true).unwrap(); + fs_extra::file::write_all(&file1, "content1").unwrap(); + fs_extra::file::write_all(&file2, "content22").unwrap(); + fs_extra::file::write_all(&file3, "content333").unwrap(); + fs_extra::file::write_all(&old_file1, "old_content1").unwrap(); + fs_extra::file::write_all(&old_file2, "old_content22").unwrap(); + + assert!(root_dir1.exists()); + assert!(root_dir1_sub.exists()); + assert!(root_dir2.exists()); + assert!(root_dir2_dir1.exists()); + assert!(root_dir2_dir1_sub.exists()); + assert!(root_dir2_dir3.exists()); + assert!(file1.exists()); + assert!(file2.exists()); + assert!(file3.exists()); + assert!(old_file1.exists()); + assert!(old_file2.exists()); + + let mut options = CopyOptions::new(); + options.copy_inside = true; + options.overwrite = true; + + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let func_test = |process_info: TransitProcess| { + tx.send(process_info).unwrap(); + TransitProcessResult::ContinueOrAbort + }; + let result = copy_with_progress(&root_dir1, &root_dir2, &options, func_test).unwrap(); + + assert_eq!(17, result); + assert!(root_dir1.exists()); + assert!(root_dir1_sub.exists()); + assert!(root_dir2.exists()); + assert!(root_dir2_dir1.exists()); + assert!(root_dir2_dir1_sub.exists()); + assert!(root_dir2_dir3.exists()); + assert!(compare_dir(&root_dir1, &root_dir2)); + }) + .join(); + + loop { + match rx.try_recv() { + Ok(process_info) => { + if process_info.file_name == "file2.txt" { + assert_eq!(9, process_info.file_total_bytes); + assert_eq!(get_dir_size() * 2 + 17, process_info.total_bytes); + } else if process_info.file_name == "file1.txt" { + assert_eq!(8, process_info.file_total_bytes); + assert_eq!(get_dir_size() * 2 + 17, process_info.total_bytes); + } else { + panic!("Unknow file name!"); + } + } + Err(TryRecvError::Disconnected) => { + break; + } + Err(TryRecvError::Empty) => {} + } + } + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } +} + +#[test] +fn it_move_with_progress_exist_user_decide_overwrite() { + let test_dir = Path::new(TEST_FOLDER).join("it_move_with_progress_exist_user_decide_overwrite"); + let out = test_dir.join("out"); + let dir = (test_dir.join("dir"), out.join("dir")); + let file1 = (dir.0.join("file1.txt"), dir.1.join("file1.txt")); + let file2 = (dir.0.join("file2.txt"), dir.1.join("file2.txt")); + + create_all(&dir.0, true).unwrap(); + create_all(&dir.1, true).unwrap(); + + assert!(&dir.0.exists()); + assert!(&dir.1.exists()); + + fs_extra::file::write_all(&file1.0, "content1").unwrap(); + fs_extra::file::write_all(&file2.0, "content2").unwrap(); + + fs_extra::file::write_all(&file1.1, "old content7").unwrap(); + fs_extra::file::write_all(&file2.1, "old content3").unwrap(); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file1.1.exists()); + assert!(file2.1.exists()); + + let mut options = CopyOptions::new(); + assert!(!compare_dir(&dir.0, &out)); + options.buffer_size = 1; + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let mut count_exist_files = 0; + let result: u64; + { + let func_test = |process_info: TransitProcess| { + let result: TransitProcessResult; + match process_info.state { + TransitState::Exists => { + count_exist_files += 1; + result = TransitProcessResult::Overwrite; + tx.send(process_info).unwrap(); + } + _ => result = TransitProcessResult::Abort, + }; + result + }; + result = move_dir_with_progress(&dir.0, &out, &options, func_test).unwrap(); + } + assert_eq!(2, count_exist_files); + + assert_eq!(16, result); + assert!(!dir.0.exists()); + assert!(dir.1.exists()); + }) + .join(); + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } + rx.try_recv().unwrap(); +} + +#[test] +fn it_move_with_progress_exist_user_decide_overwrite_all() { + let test_dir = + Path::new(TEST_FOLDER).join("it_move_with_progress_exist_user_decide_overwrite_all"); + let out = test_dir.join("out"); + let dir = (test_dir.join("dir"), out.join("dir")); + let file1 = (dir.0.join("file1.txt"), dir.1.join("file1.txt")); + let file2 = (dir.0.join("file2.txt"), dir.1.join("file2.txt")); + + create_all(&dir.0, true).unwrap(); + create_all(&dir.1, true).unwrap(); + + assert!(&dir.0.exists()); + assert!(&dir.1.exists()); + + fs_extra::file::write_all(&file1.0, "content1").unwrap(); + fs_extra::file::write_all(&file2.0, "content2").unwrap(); + + fs_extra::file::write_all(&file1.1, "old content7").unwrap(); + fs_extra::file::write_all(&file2.1, "old content3").unwrap(); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file1.1.exists()); + assert!(file2.1.exists()); + + let mut options = CopyOptions::new(); + assert!(!compare_dir(&dir.0, &out)); + options.buffer_size = 1; + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let mut count_exist_files = 0; + let result: u64; + { + let func_test = |process_info: TransitProcess| { + let result: TransitProcessResult; + match process_info.state { + TransitState::Exists => { + count_exist_files += 1; + result = TransitProcessResult::OverwriteAll; + tx.send(process_info).unwrap(); + } + _ => result = TransitProcessResult::Abort, + }; + result + }; + result = move_dir_with_progress(&dir.0, &out, &options, func_test).unwrap(); + } + assert_eq!(1, count_exist_files); + + assert_eq!(16, result); + assert!(!dir.0.exists()); + assert!(dir.1.exists()); + }) + .join(); + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } + rx.try_recv().unwrap(); +} + +#[test] +fn it_move_with_progress_exist_user_decide_skip() { + let test_dir = Path::new(TEST_FOLDER).join("it_move_with_progress_exist_user_decide_skip"); + let out = test_dir.join("out"); + let dir = (test_dir.join("dir"), out.join("dir")); + let file1 = (dir.0.join("file1.txt"), dir.1.join("file1.txt")); + let file2 = (dir.0.join("file2.txt"), dir.1.join("file2.txt")); + + create_all(&dir.0, true).unwrap(); + create_all(&dir.1, true).unwrap(); + + assert!(&dir.0.exists()); + assert!(&dir.1.exists()); + + fs_extra::file::write_all(&file1.0, "content1").unwrap(); + fs_extra::file::write_all(&file2.0, "content2").unwrap(); + + fs_extra::file::write_all(&file1.1, "old content7").unwrap(); + fs_extra::file::write_all(&file2.1, "old content3").unwrap(); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file1.1.exists()); + assert!(file2.1.exists()); + + let mut options = CopyOptions::new(); + assert!(!compare_dir(&dir.0, &out)); + options.buffer_size = 1; + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let mut count_exist_files = 0; + let result: u64; + { + let func_test = |process_info: TransitProcess| { + let result: TransitProcessResult; + match process_info.state { + TransitState::Exists => { + count_exist_files += 1; + result = TransitProcessResult::Skip; + tx.send(process_info).unwrap(); + } + _ => result = TransitProcessResult::Abort, + }; + result + }; + result = move_dir_with_progress(&dir.0, &out, &options, func_test).unwrap(); + } + assert_eq!(2, count_exist_files); + + assert_eq!(0, result); + assert!(dir.0.exists()); + assert!(dir.1.exists()); + }) + .join(); + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } + rx.try_recv().unwrap(); +} + +#[test] +fn it_move_with_progress_exist_user_decide_skip_all() { + let test_dir = Path::new(TEST_FOLDER).join("it_move_with_progress_exist_user_decide_skip_all"); + let out = test_dir.join("out"); + let dir = (test_dir.join("dir"), out.join("dir")); + let file1 = (dir.0.join("file1.txt"), dir.1.join("file1.txt")); + let file2 = (dir.0.join("file2.txt"), dir.1.join("file2.txt")); + + create_all(&dir.0, true).unwrap(); + create_all(&dir.1, true).unwrap(); + + assert!(&dir.0.exists()); + assert!(&dir.1.exists()); + + fs_extra::file::write_all(&file1.0, "content1").unwrap(); + fs_extra::file::write_all(&file2.0, "content2").unwrap(); + + fs_extra::file::write_all(&file1.1, "old content7").unwrap(); + fs_extra::file::write_all(&file2.1, "old content3").unwrap(); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file1.1.exists()); + assert!(file2.1.exists()); + + let mut options = CopyOptions::new(); + assert!(!compare_dir(&dir.0, &out)); + options.buffer_size = 1; + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let mut count_exist_files = 0; + let result: u64; + { + let func_test = |process_info: TransitProcess| { + let result: TransitProcessResult; + match process_info.state { + TransitState::Exists => { + count_exist_files += 1; + result = TransitProcessResult::SkipAll; + tx.send(process_info).unwrap(); + } + _ => result = TransitProcessResult::Abort, + }; + result + }; + result = move_dir_with_progress(&dir.0, &out, &options, func_test).unwrap(); + } + assert_eq!(1, count_exist_files); + + assert_eq!(0, result); + assert!(dir.0.exists()); + assert!(dir.1.exists()); + }) + .join(); + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } + rx.try_recv().unwrap(); +} + +#[test] +fn it_move_with_progress_exist_user_decide_retry() { + let test_dir = Path::new(TEST_FOLDER).join("it_move_with_progress_exist_user_decide_retry"); + let out = test_dir.join("out"); + let dir = (test_dir.join("dir"), out.join("dir")); + let file1 = (dir.0.join("file1.txt"), dir.1.join("file1.txt")); + let file2 = (dir.0.join("file2.txt"), dir.1.join("file2.txt")); + + create_all(&dir.0, true).unwrap(); + create_all(&dir.1, true).unwrap(); + + assert!(&dir.0.exists()); + assert!(&dir.1.exists()); + + fs_extra::file::write_all(&file1.0, "content1").unwrap(); + fs_extra::file::write_all(&file2.0, "content2").unwrap(); + + fs_extra::file::write_all(&file1.1, "old content7").unwrap(); + fs_extra::file::write_all(&file2.1, "old content3").unwrap(); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file1.1.exists()); + assert!(file2.1.exists()); + + let mut options = CopyOptions::new(); + assert!(!compare_dir(&dir.0, &out)); + options.buffer_size = 1; + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let mut count_exist_files = 0; + let result: u64; + { + let func_test = |process_info: TransitProcess| { + let result: TransitProcessResult; + match process_info.state { + TransitState::Exists => { + if count_exist_files == 3 || count_exist_files == 6 { + result = TransitProcessResult::Skip; + } else { + result = TransitProcessResult::Retry; + } + count_exist_files += 1; + tx.send(process_info).unwrap(); + } + _ => result = TransitProcessResult::Abort, + }; + result + }; + result = move_dir_with_progress(&dir.0, &out, &options, func_test).unwrap(); + } + assert_eq!(7, count_exist_files); + + assert_eq!(0, result); + assert!(dir.0.exists()); + assert!(dir.1.exists()); + }) + .join(); + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } + rx.try_recv().unwrap(); +} + +#[test] +fn it_move_dir_with_progress_inside_work_target_dir_not_exist() { + let path_root = Path::new(TEST_FOLDER); + let root = path_root.join("it_move_dir_with_progress_inside_work_target_dir_not_exist"); + let root_dir1 = root.join("dir1"); + let root_dir1_sub = root_dir1.join("sub"); + let root_dir2 = root.join("dir2"); + let file1 = root_dir1.join("file1.txt"); + let file2 = root_dir1_sub.join("file2.txt"); + + create_all(&root_dir1_sub, true).unwrap(); + fs_extra::file::write_all(&file1, "content").unwrap(); + fs_extra::file::write_all(&file2, "content2").unwrap(); + + if root_dir2.exists() { + remove(&root_dir2).unwrap(); + } + + assert!(root_dir1.exists()); + assert!(root_dir1_sub.exists()); + assert!(!root_dir2.exists()); + assert!(file1.exists()); + assert!(file2.exists()); + + let mut options = CopyOptions::new(); + options.copy_inside = true; + + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let func_test = |process_info: TransitProcess| { + tx.send(process_info).unwrap(); + TransitProcessResult::ContinueOrAbort + }; + let result = move_dir_with_progress(&root_dir1, &root_dir2, &options, func_test).unwrap(); + + assert_eq!(15, result); + assert!(!root_dir1.exists()); + let root_dir2_sub = root_dir2.join("sub"); + let root_dir2_file1 = root_dir2.join("file1.txt"); + let root_dir2_sub_file2 = root_dir2_sub.join("file2.txt"); + assert!(root_dir2.exists()); + assert!(root_dir2_sub.exists()); + assert!(root_dir2_file1.exists()); + assert!(root_dir2_sub_file2.exists()); + }) + .join(); + + loop { + match rx.try_recv() { + Ok(process_info) => { + if process_info.file_name == "file2.txt" { + assert_eq!(8, process_info.file_total_bytes); + assert_eq!(get_dir_size() * 2 + 15, process_info.total_bytes); + } else if process_info.file_name == "file1.txt" { + assert_eq!(7, process_info.file_total_bytes); + assert_eq!(get_dir_size() * 2 + 15, process_info.total_bytes); + } else { + panic!("Unknow file name!"); + } + } + Err(TryRecvError::Disconnected) => { + break; + } + Err(TryRecvError::Empty) => {} + } + } + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } +} + +#[test] +fn it_move_dir_with_progress_inside_work_target_dir_exist_with_no_source_dir_named_sub_dir() { + let path_root = Path::new(TEST_FOLDER); + let root = path_root.join( + "it_move_dir_with_progress_inside_work_target_dir_exist_with_no_source_dir_named_sub_dir", + ); + let root_dir1 = root.join("dir1"); + let root_dir1_sub = root_dir1.join("sub"); + let root_dir2 = root.join("dir2"); + let root_dir2_dir1 = root_dir2.join("dir1"); + let root_dir2_dir3 = root_dir2.join("dir3"); + let file1 = root_dir1.join("file1.txt"); + let file2 = root_dir1_sub.join("file2.txt"); + let file3 = root_dir2_dir3.join("file3.txt"); + + create_all(&root_dir1_sub, true).unwrap(); + create_all(&root_dir2_dir3, true).unwrap(); + fs_extra::file::write_all(&file1, "content1").unwrap(); + fs_extra::file::write_all(&file2, "content22").unwrap(); + fs_extra::file::write_all(&file3, "content333").unwrap(); + + if root_dir2_dir1.exists() { + remove(&root_dir2_dir1).unwrap(); + } + + assert!(root_dir1.exists()); + assert!(root_dir1_sub.exists()); + assert!(root_dir2.exists()); + assert!(!root_dir2_dir1.exists()); + assert!(root_dir2_dir3.exists()); + assert!(file1.exists()); + assert!(file2.exists()); + assert!(file3.exists()); + + let mut options = CopyOptions::new(); + options.copy_inside = true; + + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let func_test = |process_info: TransitProcess| { + tx.send(process_info).unwrap(); + TransitProcessResult::ContinueOrAbort + }; + let result = move_dir_with_progress(&root_dir1, &root_dir2, &options, func_test).unwrap(); + + assert_eq!(17, result); + assert!(!root_dir1.exists()); + assert!(root_dir2.exists()); + assert!(root_dir2_dir1.exists()); + assert!(root_dir2_dir3.exists()); + let root_dir2_dir1_file1 = root_dir2_dir1.join("file1.txt"); + let root_dir2_dir1_sub = root_dir2_dir1.join("sub"); + let root_dir2_dir1_sub_file2 = root_dir2_dir1_sub.join("file2.txt"); + let root_dir2_dir3_file3 = root_dir2_dir3.join("file3.txt"); + assert!(root_dir2_dir1_file1.exists()); + assert!(root_dir2_dir1_sub.exists()); + assert!(root_dir2_dir1_sub_file2.exists()); + assert!(root_dir2_dir3_file3.exists()); + }) + .join(); + + loop { + match rx.try_recv() { + Ok(process_info) => { + if process_info.file_name == "file2.txt" { + assert_eq!(9, process_info.file_total_bytes); + assert_eq!(get_dir_size() * 2 + 17, process_info.total_bytes); + } else if process_info.file_name == "file1.txt" { + assert_eq!(8, process_info.file_total_bytes); + assert_eq!(get_dir_size() * 2 + 17, process_info.total_bytes); + } else { + panic!("Unknow file name!"); + } + } + Err(TryRecvError::Disconnected) => { + break; + } + Err(TryRecvError::Empty) => {} + } + } + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } +} + +#[test] +fn it_move_dir_with_progress_inside_no_overwrite_work_target_dir_exist_with_source_dir_exist() { + let path_root = Path::new(TEST_FOLDER); + let root = path_root.join( + "it_move_dir_with_progress_inside_no_overwrite_work_target_dir_exist_with_source_dir_exist", + ); + let root_dir1 = root.join("dir1"); + let root_dir1_sub = root_dir1.join("sub"); + let root_dir2 = root.join("dir2"); + let root_dir2_dir1 = root_dir2.join("dir1"); + let root_dir2_dir1_sub = root_dir2_dir1.join("sub"); + let root_dir2_dir3 = root_dir2.join("dir3"); + let file1 = root_dir1.join("file1.txt"); + let file2 = root_dir1_sub.join("file2.txt"); + let file3 = root_dir2_dir3.join("file3.txt"); + let old_file1 = root_dir2_dir1.join("file1.txt"); + let old_file2 = root_dir2_dir1_sub.join("file2.txt"); + + create_all(&root_dir1_sub, true).unwrap(); + create_all(&root_dir2_dir3, true).unwrap(); + create_all(&root_dir2_dir1, true).unwrap(); + create_all(&root_dir2_dir1_sub, true).unwrap(); + fs_extra::file::write_all(&file1, "content1").unwrap(); + fs_extra::file::write_all(&file2, "content22").unwrap(); + fs_extra::file::write_all(&file3, "content333").unwrap(); + fs_extra::file::write_all(&old_file1, "old_content1").unwrap(); + fs_extra::file::write_all(&old_file2, "old_content22").unwrap(); + + assert!(root_dir1.exists()); + assert!(root_dir1_sub.exists()); + assert!(root_dir2.exists()); + assert!(root_dir2_dir1.exists()); + assert!(root_dir2_dir1_sub.exists()); + assert!(root_dir2_dir3.exists()); + assert!(file1.exists()); + assert!(file2.exists()); + assert!(file3.exists()); + assert!(old_file1.exists()); + assert!(old_file2.exists()); + + let mut options = CopyOptions::new(); + options.copy_inside = true; + + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let func_test = |process_info: TransitProcess| { + tx.send(process_info).unwrap(); + TransitProcessResult::Skip + }; + let result = move_dir_with_progress(&root_dir1, &root_dir2, &options, func_test).unwrap(); + + assert_eq!(0, result); + + assert!(root_dir1.exists()); + assert!(file1.exists()); + assert!(root_dir1_sub.exists()); + assert!(file2.exists()); + + assert!(root_dir2.exists()); + assert!(root_dir2_dir1.exists()); + assert!(root_dir2_dir1_sub.exists()); + assert!(root_dir2_dir3.exists()); + let root_dir2_dir1_file1 = root_dir2_dir1.join("file1.txt"); + let root_dir2_dir1_sub_file2 = root_dir2_dir1_sub.join("file2.txt"); + let root_dir2_dir3_file3 = root_dir2_dir3.join("file3.txt"); + assert!(root_dir2_dir1_file1.exists()); + assert!(root_dir2_dir1_sub_file2.exists()); + assert!(root_dir2_dir3_file3.exists()); + assert!(!files_eq(file1, old_file1)); + assert!(!files_eq(file2, old_file2)); + }) + .join(); + + loop { + match rx.try_recv() { + Ok(process_info) => { + if process_info.file_name == "file2.txt" { + assert_eq!(9, process_info.file_total_bytes); + assert_eq!(get_dir_size() * 2 + 17, process_info.total_bytes); + } else if process_info.file_name == "file1.txt" { + assert_eq!(8, process_info.file_total_bytes); + assert_eq!(get_dir_size() * 2 + 17, process_info.total_bytes); + } else { + panic!("Unknow file name!"); + } + } + Err(TryRecvError::Disconnected) => { + break; + } + Err(TryRecvError::Empty) => {} + } + } + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } +} + +#[test] +fn it_move_dir_with_progress_inside_overwrite_work_target_dir_exist_with_source_dir_exist() { + let path_root = Path::new(TEST_FOLDER); + let root = path_root.join( + "it_move_dir_with_progress_inside_overwrite_work_target_dir_exist_with_source_dir_exist", + ); + let root_dir1 = root.join("dir1"); + let root_dir1_sub = root_dir1.join("sub"); + let root_dir2 = root.join("dir2"); + let root_dir2_dir1 = root_dir2.join("dir1"); + let root_dir2_dir1_sub = root_dir2_dir1.join("sub"); + let root_dir2_dir3 = root_dir2.join("dir3"); + let file1 = root_dir1.join("file1.txt"); + let file2 = root_dir1_sub.join("file2.txt"); + let file3 = root_dir2_dir3.join("file3.txt"); + let old_file1 = root_dir2_dir1.join("file1.txt"); + let old_file2 = root_dir2_dir1_sub.join("file2.txt"); + + create_all(&root_dir1_sub, true).unwrap(); + create_all(&root_dir2_dir3, true).unwrap(); + create_all(&root_dir2_dir1, true).unwrap(); + create_all(&root_dir2_dir1_sub, true).unwrap(); + fs_extra::file::write_all(&file1, "content1").unwrap(); + fs_extra::file::write_all(&file2, "content22").unwrap(); + fs_extra::file::write_all(&file3, "content333").unwrap(); + fs_extra::file::write_all(&old_file1, "old_content1").unwrap(); + fs_extra::file::write_all(&old_file2, "old_content22").unwrap(); + + assert!(root_dir1.exists()); + assert!(root_dir1_sub.exists()); + assert!(root_dir2.exists()); + assert!(root_dir2_dir1.exists()); + assert!(root_dir2_dir1_sub.exists()); + assert!(root_dir2_dir3.exists()); + assert!(file1.exists()); + assert!(file2.exists()); + assert!(file3.exists()); + assert!(old_file1.exists()); + assert!(old_file2.exists()); + + let mut options = CopyOptions::new(); + options.copy_inside = true; + options.overwrite = true; + + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let func_test = |process_info: TransitProcess| { + tx.send(process_info).unwrap(); + TransitProcessResult::ContinueOrAbort + }; + let result = move_dir_with_progress(&root_dir1, &root_dir2, &options, func_test).unwrap(); + + assert_eq!(17, result); + + assert!(!root_dir1.exists()); + + assert!(root_dir2.exists()); + assert!(root_dir2_dir1.exists()); + assert!(root_dir2_dir1_sub.exists()); + assert!(root_dir2_dir3.exists()); + let root_dir2_dir1_file1 = root_dir2_dir1.join("file1.txt"); + let root_dir2_dir1_sub_file2 = root_dir2_dir1_sub.join("file2.txt"); + let root_dir2_dir3_file3 = root_dir2_dir3.join("file3.txt"); + assert!(root_dir2_dir1_file1.exists()); + assert!(root_dir2_dir1_sub_file2.exists()); + assert!(root_dir2_dir3_file3.exists()); + }) + .join(); + + loop { + match rx.try_recv() { + Ok(process_info) => { + if process_info.file_name == "file2.txt" { + assert_eq!(9, process_info.file_total_bytes); + assert_eq!(get_dir_size() * 2 + 17, process_info.total_bytes); + } else if process_info.file_name == "file1.txt" { + assert_eq!(8, process_info.file_total_bytes); + assert_eq!(get_dir_size() * 2 + 17, process_info.total_bytes); + } else { + panic!("Unknow file name!"); + } + } + Err(TryRecvError::Disconnected) => { + break; + } + Err(TryRecvError::Empty) => {} + } + } + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } +} +#[test] +fn it_move_with_progress_content_only_option() { + let test_dir = Path::new(TEST_FOLDER).join("it_move_with_progress_content_only_option"); + let path_to = test_dir.join("out"); + let d_level_1 = (test_dir.join("d_level_1"), path_to.clone()); + let d_level_2 = (d_level_1.0.join("d_level_2"), d_level_1.1.join("d_level_2")); + let d_level_3 = (d_level_2.0.join("d_level_3"), d_level_2.1.join("d_level_3")); + + let file1 = (d_level_1.0.join("file1.txt"), d_level_1.1.join("file1.txt")); + let file2 = (d_level_2.0.join("file2.txt"), d_level_2.1.join("file2.txt")); + let file3 = (d_level_3.0.join("file3.txt"), d_level_3.1.join("file3.txt")); + + create_all(&d_level_1.0, true).unwrap(); + create_all(&d_level_2.0, true).unwrap(); + create_all(&d_level_3.0, true).unwrap(); + create_all(&path_to, true).unwrap(); + + assert!(path_to.exists()); + assert!(d_level_1.0.exists()); + assert!(d_level_2.0.exists()); + assert!(d_level_3.0.exists()); + + assert!(!d_level_2.1.exists()); + assert!(!d_level_3.1.exists()); + + fs_extra::file::write_all(&file1.0, "content1").unwrap(); + fs_extra::file::write_all(&file2.0, "content2").unwrap(); + fs_extra::file::write_all(&file3.0, "content3").unwrap(); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file3.0.exists()); + + assert!(!file1.1.exists()); + assert!(!file2.1.exists()); + assert!(!file3.1.exists()); + + let mut options = CopyOptions::new(); + options.content_only = true; + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let func_test = |process_info: TransitProcess| { + tx.send(process_info).unwrap(); + TransitProcessResult::ContinueOrAbort + }; + + let result = move_dir_with_progress(&d_level_1.0, &path_to, &options, func_test).unwrap(); + + assert_eq!(24, result); + + assert!(!d_level_1.0.exists()); + assert!(!d_level_2.0.exists()); + assert!(!d_level_3.0.exists()); + + assert!(d_level_1.1.exists()); + assert!(d_level_2.1.exists()); + assert!(d_level_3.1.exists()); + + assert!(!file1.0.exists()); + assert!(!file2.0.exists()); + assert!(!file3.0.exists()); + + assert!(file1.1.exists()); + assert!(file2.1.exists()); + assert!(file3.1.exists()); + }) + .join(); + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } + + match rx.recv() { + Err(_) => panic!("Errors should not be!"), + _ => {} + } +} diff --git a/vendor/fs_extra/tests/file.rs b/vendor/fs_extra/tests/file.rs new file mode 100644 index 000000000..67840a532 --- /dev/null +++ b/vendor/fs_extra/tests/file.rs @@ -0,0 +1,1036 @@ +// use std::io::{ErrorKind, Result}; +use std::path::{Path, PathBuf}; +use std::sync::mpsc; +use std::thread; + +extern crate fs_extra; +use fs_extra::error::*; +use fs_extra::file::*; + +const TEST_FOLDER: &'static str = "./tests/temp/file"; + +fn files_eq(file1: P, file2: Q) -> Result +where + P: AsRef, + Q: AsRef, +{ + let content1 = read_to_string(file1)?; + let content2 = read_to_string(file2)?; + Ok(content1 == content2) +} + +#[test] +fn it_read_and_write_work() { + let mut test_file = PathBuf::from(TEST_FOLDER); + test_file.push("it_read_and_write_work"); + test_file.push("test.txt"); + fs_extra::dir::create_all(test_file.parent().unwrap(), true).unwrap(); + let content1 = "test_1"; + let content2 = "test_2"; + write_all(&test_file, &content1).unwrap(); + assert!(test_file.exists()); + let read1 = read_to_string(&test_file).unwrap(); + assert_eq!(content1, read1); + write_all(&test_file, &content2).unwrap(); + let read2 = read_to_string(&test_file).unwrap(); + assert_eq!(content2, read2); +} + +#[test] +fn it_read_not_exist_file() { + let mut test_file = PathBuf::from(TEST_FOLDER); + test_file.push("it_read_not_exist_file"); + test_file.push("test.txt"); + fs_extra::dir::create_all(test_file.parent().unwrap(), true).unwrap(); + assert!(!test_file.exists()); + match read_to_string(&test_file) { + Ok(_) => panic!("should be error"), + Err(err) => match err.kind { + ErrorKind::NotFound => {} + _ => panic!("wrong error"), + }, + } +} + +#[test] +fn it_read_not_file() { + let mut test_file = PathBuf::from(TEST_FOLDER); + test_file.push("it_read_not_file"); + fs_extra::dir::create_all(&test_file, true).unwrap(); + match read_to_string(&test_file) { + Ok(_) => panic!("should be error"), + Err(err) => match err.kind { + ErrorKind::InvalidFile => {} + _ => panic!("wrong error"), + }, + } +} + +#[test] +fn it_write_not_file() { + let mut test_file = PathBuf::from(TEST_FOLDER); + test_file.push("it_write_not_file"); + test_file.push("test.txt"); + fs_extra::dir::create_all(test_file.parent().unwrap(), true).unwrap(); + assert!(!test_file.exists()); + test_file.pop(); + match write_all(test_file, "content") { + Ok(_) => panic!("should be error"), + Err(err) => match err.kind { + ErrorKind::InvalidFile => {} + _ => panic!("wrong error"), + }, + } +} + +#[test] +fn it_remove_file() { + let mut test_file = PathBuf::from(TEST_FOLDER); + test_file.push("it_remove_file"); + test_file.push("test.txt"); + fs_extra::dir::create_all(test_file.parent().unwrap(), true).unwrap(); + write_all(&test_file, "test").unwrap(); + assert!(test_file.exists()); + remove(&test_file).unwrap(); + assert!(!test_file.exists()); +} + +#[test] +fn it_copy_work() { + let mut test_file = PathBuf::from(TEST_FOLDER); + test_file.push("it_copy_work"); + let mut test_file_out = test_file.clone(); + test_file.push("test.txt"); + test_file_out.push("out"); + test_file_out.push("test.txt"); + fs_extra::dir::create_all(&test_file.parent().unwrap(), true).unwrap(); + fs_extra::dir::create_all(&test_file_out.parent().unwrap(), true).unwrap(); + + write_all(&test_file, "test_data").unwrap(); + assert!(test_file.exists()); + assert!(!test_file_out.exists()); + let options = CopyOptions::new(); + copy(&test_file, &test_file_out, &options).unwrap(); + assert!(test_file.exists()); + assert!(test_file_out.exists()); + assert_eq!(test_file.file_name(), test_file_out.file_name()); + assert!(files_eq(test_file, test_file_out).unwrap()); +} + +#[test] +fn it_copy_not_file() { + let mut test_file = PathBuf::from(TEST_FOLDER); + test_file.push("it_copy_work"); + let mut test_file_out = test_file.clone(); + test_file.push("test.txt"); + test_file_out.push("out"); + test_file_out.push("test.txt"); + fs_extra::dir::create_all(&test_file.parent().unwrap(), true).unwrap(); + fs_extra::dir::create_all(&test_file_out.parent().unwrap(), true).unwrap(); + + write_all(&test_file, "test_data").unwrap(); + assert!(test_file.exists()); + assert!(!test_file_out.exists()); + test_file.pop(); + let options = CopyOptions::new(); + + match copy(&test_file, &test_file_out, &options) { + Err(err) => match err.kind { + ErrorKind::InvalidFile => { + let wrong_path = format!("Path \"{}\" is not a file!", test_file.to_str().unwrap()); + assert_eq!(wrong_path, err.to_string()); + } + _ => { + panic!("wrong error"); + } + }, + Ok(_) => { + panic!("should be error"); + } + } +} + +#[test] +fn it_copy_source_not_exist() { + let mut test_file = PathBuf::from(TEST_FOLDER); + test_file.push("it_copy_source_not_exist"); + let mut test_file_out = test_file.clone(); + test_file.push("test1.txt"); + test_file_out.push("out"); + test_file_out.push("test.txt"); + fs_extra::dir::create_all(&test_file.parent().unwrap(), true).unwrap(); + fs_extra::dir::create_all(&test_file_out.parent().unwrap(), true).unwrap(); + + assert!(!test_file.exists()); + let options = CopyOptions::new(); + match copy(&test_file, test_file_out, &options) { + Ok(_) => panic!("should be error"), + Err(err) => match err.kind { + ErrorKind::NotFound => { + let wrong_path = format!( + "Path \"{}\" does not exist or you don't have \ + access!", + test_file.to_str().unwrap() + ); + assert_eq!(wrong_path, err.to_string()); + () + } + _ => panic!("wrong error"), + }, + } +} + +#[test] +fn it_copy_exist_overwrite() { + let mut test_file = PathBuf::from(TEST_FOLDER); + test_file.push("it_copy_exist_overwrite"); + let mut test_file_out = test_file.clone(); + test_file.push("test.txt"); + test_file_out.push("out"); + test_file_out.push("test.txt"); + fs_extra::dir::create_all(&test_file.parent().unwrap(), true).unwrap(); + fs_extra::dir::create_all(&test_file_out.parent().unwrap(), true).unwrap(); + + write_all(&test_file, "test_data").unwrap(); + let mut options = CopyOptions::new(); + copy(&test_file, &test_file_out, &options).unwrap(); + assert!(test_file.exists()); + assert!(files_eq(&test_file, &test_file_out).unwrap()); + options.overwrite = true; + write_all(&test_file, "test_data2").unwrap(); + match copy(&test_file, &test_file_out, &options) { + Ok(_) => { + assert!(test_file.exists()); + assert_eq!(read_to_string(test_file_out).unwrap(), "test_data2"); + () + } + Err(err) => panic!(err.to_string()), + } +} + +#[test] +fn it_copy_exist_not_overwrite() { + let mut test_file = PathBuf::from(TEST_FOLDER); + test_file.push("it_copy_exist_not_overwrite"); + let mut test_file_out = test_file.clone(); + test_file.push("test.txt"); + test_file_out.push("out"); + test_file_out.push("test.txt"); + fs_extra::dir::create_all(&test_file.parent().unwrap(), true).unwrap(); + fs_extra::dir::create_all(&test_file_out.parent().unwrap(), true).unwrap(); + + write_all(&test_file, "test_data").unwrap(); + let mut options = CopyOptions::new(); + copy(&test_file, &test_file_out, &options).unwrap(); + assert!(test_file.exists()); + options.overwrite = false; + write_all(&test_file, "test_data2").unwrap(); + match copy(&test_file, &test_file_out, &options) { + Ok(_) => panic!("should be error"), + Err(err) => { + let file_path = format!("Path \"{}\" exists", test_file_out.to_str().unwrap()); + assert_eq!(file_path, err.to_string()); + assert!(!files_eq(test_file, test_file_out).unwrap()); + () + } + } +} + +#[test] +fn it_copy_exist_skip_exist() { + let mut test_file = PathBuf::from(TEST_FOLDER); + test_file.push("it_copy_exist_skip_exist"); + let mut test_file_out = test_file.clone(); + test_file.push("test.txt"); + test_file_out.push("out"); + test_file_out.push("test.txt"); + fs_extra::dir::create_all(&test_file.parent().unwrap(), true).unwrap(); + fs_extra::dir::create_all(&test_file_out.parent().unwrap(), true).unwrap(); + + write_all(&test_file, "test_data").unwrap(); + let mut options = CopyOptions::new(); + copy(&test_file, &test_file_out, &options).unwrap(); + assert!(test_file.exists()); + options.skip_exist = true; + write_all(&test_file, "test_data2").unwrap(); + match copy(&test_file, &test_file_out, &options) { + Ok(_) => { + assert!(!files_eq(test_file, test_file_out).unwrap()); + () + } + Err(_) => panic!("should be error"), + } +} + +#[test] +fn it_copy_exist_overwrite_and_skip_exist() { + let mut test_file = PathBuf::from(TEST_FOLDER); + test_file.push("it_copy_exist_overwrite_and_skip_exist"); + let mut test_file_out = test_file.clone(); + test_file.push("test.txt"); + test_file_out.push("out"); + test_file_out.push("test.txt"); + fs_extra::dir::create_all(&test_file.parent().unwrap(), true).unwrap(); + fs_extra::dir::create_all(&test_file_out.parent().unwrap(), true).unwrap(); + + write_all(&test_file, "test_data").unwrap(); + let mut options = CopyOptions::new(); + copy(&test_file, &test_file_out, &options).unwrap(); + assert!(test_file.exists()); + assert!(files_eq(&test_file, &test_file_out).unwrap()); + options.overwrite = true; + options.skip_exist = true; + write_all(&test_file, "test_data2").unwrap(); + match copy(&test_file, &test_file_out, &options) { + Ok(_) => { + assert!(test_file.exists()); + assert_eq!(read_to_string(test_file_out).unwrap(), "test_data2"); + () + } + Err(err) => panic!(err.to_string()), + } +} + +#[test] +fn it_copy_with_progress_work() { + let mut test_file = PathBuf::from(TEST_FOLDER); + test_file.push("it_copy_with_progress_work"); + let mut test_file_out = test_file.clone(); + test_file.push("test.txt"); + test_file_out.push("out"); + test_file_out.push("test.txt"); + fs_extra::dir::create_all(&test_file.parent().unwrap(), true).unwrap(); + fs_extra::dir::create_all(&test_file_out.parent().unwrap(), true).unwrap(); + + write_all(&test_file, "test_data").unwrap(); + assert!(test_file.exists()); + assert!(!test_file_out.exists()); + let mut options = CopyOptions::new(); + options.buffer_size = 1; + let (tx, rx) = mpsc::channel(); + thread::spawn(move || { + let func_test = |process_info: TransitProcess| { + tx.send(process_info).unwrap(); + }; + copy_with_progress(&test_file, &test_file_out, &options, func_test).unwrap(); + assert!(test_file.exists()); + assert!(test_file_out.exists()); + assert_eq!(test_file.file_name(), test_file_out.file_name()); + assert!(files_eq(test_file, test_file_out).unwrap()); + }); + for i in 1..10 { + let process_info: TransitProcess = rx.recv().unwrap(); + assert_eq!(i, process_info.copied_bytes); + assert_eq!(9, process_info.total_bytes); + } +} + +#[test] +fn it_copy_progress_not_file() { + let mut test_file = PathBuf::from(TEST_FOLDER); + test_file.push("it_copy_progress_not_file"); + let mut test_file_out = test_file.clone(); + test_file.push("test.txt"); + test_file_out.push("out"); + test_file_out.push("test.txt"); + fs_extra::dir::create_all(&test_file.parent().unwrap(), true).unwrap(); + fs_extra::dir::create_all(&test_file_out.parent().unwrap(), true).unwrap(); + + write_all(&test_file, "test_data").unwrap(); + assert!(test_file.exists()); + assert!(!test_file_out.exists()); + test_file.pop(); + let options = CopyOptions::new(); + let func_test = |process_info: TransitProcess| println!("{}", process_info.total_bytes); + + match copy_with_progress(&test_file, &test_file_out, &options, func_test) { + Err(err) => match err.kind { + ErrorKind::InvalidFile => { + let wrong_path = format!("Path \"{}\" is not a file!", test_file.to_str().unwrap()); + assert_eq!(wrong_path, err.to_string()); + } + _ => { + panic!("wrong error"); + } + }, + Ok(_) => { + panic!("should be error"); + } + } +} + +#[test] +fn it_copy_with_progress_work_dif_buf_size() { + let mut test_file = PathBuf::from(TEST_FOLDER); + test_file.push("it_copy_with_progress_work_dif_buf_size"); + let mut test_file_out = test_file.clone(); + test_file.push("test.txt"); + test_file_out.push("out"); + test_file_out.push("test.txt"); + fs_extra::dir::create_all(&test_file.parent().unwrap(), true).unwrap(); + fs_extra::dir::create_all(&test_file_out.parent().unwrap(), true).unwrap(); + + write_all(&test_file, "test_data_").unwrap(); + assert!(test_file.exists()); + assert!(!test_file_out.exists()); + let mut options = CopyOptions::new(); + options.buffer_size = 1; + let (tx, rx) = mpsc::channel(); + thread::spawn(move || { + let func_test = |process_info: TransitProcess| { + tx.send(process_info).unwrap(); + }; + copy_with_progress(&test_file, &test_file_out, &options, func_test).unwrap(); + assert!(test_file.exists()); + assert!(test_file_out.exists()); + assert_eq!(test_file.file_name(), test_file_out.file_name()); + assert!(files_eq(&test_file, &test_file_out).unwrap()); + + let mut options = CopyOptions::new(); + options.buffer_size = 2; + options.overwrite = true; + let (tx, rx) = mpsc::channel(); + thread::spawn(move || { + let func_test = |process_info: TransitProcess| { + tx.send(process_info).unwrap(); + }; + copy_with_progress(&test_file, &test_file_out, &options, func_test).unwrap(); + }); + for i in 1..6 { + let process_info: TransitProcess = rx.recv().unwrap(); + assert_eq!(i * 2, process_info.copied_bytes); + assert_eq!(10, process_info.total_bytes); + } + }); + for i in 1..11 { + let process_info: TransitProcess = rx.recv().unwrap(); + assert_eq!(i, process_info.copied_bytes); + assert_eq!(10, process_info.total_bytes); + } +} + +#[test] +fn it_copy_with_progress_source_not_exist() { + let mut test_file = PathBuf::from(TEST_FOLDER); + test_file.push("it_copy_with_progress_source_not_exist"); + let mut test_file_out = test_file.clone(); + test_file.push("test1.txt"); + test_file_out.push("out"); + test_file_out.push("test.txt"); + fs_extra::dir::create_all(&test_file.parent().unwrap(), true).unwrap(); + fs_extra::dir::create_all(&test_file_out.parent().unwrap(), true).unwrap(); + + assert!(!test_file.exists()); + let options = CopyOptions::new(); + let func_test = |process_info: TransitProcess| { + println!("{}", process_info.total_bytes); + }; + match copy_with_progress(&test_file, &test_file_out, &options, func_test) { + Ok(_) => panic!("should be error"), + Err(err) => match err.kind { + ErrorKind::NotFound => { + let wrong_path = format!( + "Path \"{}\" does not exist or you don't have \ + access!", + test_file.to_str().unwrap() + ); + + assert_eq!(wrong_path, err.to_string()); + () + } + _ => panic!("wrong error"), + }, + } +} + +#[test] +fn it_copy_with_progress_exist_overwrite() { + let mut test_file = PathBuf::from(TEST_FOLDER); + test_file.push("it_copy_with_progress_exist_overwrite"); + let mut test_file_out = test_file.clone(); + test_file.push("test.txt"); + test_file_out.push("out"); + test_file_out.push("test.txt"); + fs_extra::dir::create_all(&test_file.parent().unwrap(), true).unwrap(); + fs_extra::dir::create_all(&test_file_out.parent().unwrap(), true).unwrap(); + + write_all(&test_file, "test_data").unwrap(); + let mut options = CopyOptions::new(); + copy(&test_file, &test_file_out, &options).unwrap(); + assert!(test_file.exists()); + assert!(files_eq(&test_file, &test_file_out).unwrap()); + options.overwrite = true; + write_all(&test_file, "test_data2").unwrap(); + let func_test = |process_info: TransitProcess| { + println!("{}", process_info.total_bytes); + }; + match copy_with_progress(&test_file, &test_file_out, &options, func_test) { + Ok(_) => { + assert!(test_file.exists()); + assert_eq!(read_to_string(test_file_out).unwrap(), "test_data2"); + () + } + Err(err) => panic!(err.to_string()), + } +} + +#[test] +fn it_copy_with_progress_exist_not_overwrite() { + let mut test_file = PathBuf::from(TEST_FOLDER); + test_file.push("it_copy_with_progress_exist_not_overwrite"); + let mut test_file_out = test_file.clone(); + test_file.push("test.txt"); + test_file_out.push("out"); + test_file_out.push("test.txt"); + fs_extra::dir::create_all(&test_file.parent().unwrap(), true).unwrap(); + fs_extra::dir::create_all(&test_file_out.parent().unwrap(), true).unwrap(); + + write_all(&test_file, "test_data").unwrap(); + let mut options = CopyOptions::new(); + copy(&test_file, &test_file_out, &options).unwrap(); + assert!(test_file.exists()); + options.overwrite = false; + write_all(&test_file, "test_data2").unwrap(); + let func_test = |process_info: TransitProcess| { + println!("{}", process_info.total_bytes); + }; + match copy_with_progress(&test_file, &test_file_out, &options, func_test) { + Ok(_) => panic!("should be error"), + Err(err) => { + let file_path = format!("Path \"{}\" exists", test_file_out.to_str().unwrap()); + + assert_eq!(file_path, err.to_string()); + assert!(!files_eq(test_file, test_file_out).unwrap()); + () + } + } +} + +#[test] +fn it_copy_with_progress_exist_skip_exist() { + let mut test_file = PathBuf::from(TEST_FOLDER); + test_file.push("it_copy_with_progress_exist_skip_exist"); + let mut test_file_out = test_file.clone(); + test_file.push("test.txt"); + test_file_out.push("out"); + test_file_out.push("test.txt"); + fs_extra::dir::create_all(&test_file.parent().unwrap(), true).unwrap(); + fs_extra::dir::create_all(&test_file_out.parent().unwrap(), true).unwrap(); + + write_all(&test_file, "test_data").unwrap(); + let mut options = CopyOptions::new(); + copy(&test_file, &test_file_out, &options).unwrap(); + assert!(test_file.exists()); + options.skip_exist = true; + write_all(&test_file, "test_data2").unwrap(); + let func_test = |process_info: TransitProcess| { + println!("{}", process_info.total_bytes); + }; + match copy_with_progress(&test_file, &test_file_out, &options, func_test) { + Ok(_) => { + assert!(!files_eq(test_file, test_file_out).unwrap()); + () + } + Err(_) => panic!("should be error"), + } +} + +#[test] +fn it_copy_with_progress_exist_overwrite_and_skip_exist() { + let mut test_file = PathBuf::from(TEST_FOLDER); + test_file.push("it_copy_with_progress_exist_overwrite_and_skip_exist"); + let mut test_file_out = test_file.clone(); + test_file.push("test.txt"); + test_file_out.push("out"); + test_file_out.push("test.txt"); + fs_extra::dir::create_all(&test_file.parent().unwrap(), true).unwrap(); + fs_extra::dir::create_all(&test_file_out.parent().unwrap(), true).unwrap(); + + write_all(&test_file, "test_data").unwrap(); + let mut options = CopyOptions::new(); + copy(&test_file, &test_file_out, &options).unwrap(); + assert!(test_file.exists()); + assert!(files_eq(&test_file, &test_file_out).unwrap()); + options.overwrite = true; + options.skip_exist = true; + write_all(&test_file, "test_data2").unwrap(); + let func_test = |process_info: TransitProcess| { + println!("{}", process_info.total_bytes); + }; + match copy_with_progress(&test_file, &test_file_out, &options, func_test) { + Ok(_) => { + assert!(test_file.exists()); + assert_eq!(read_to_string(test_file_out).unwrap(), "test_data2"); + () + } + Err(err) => panic!(err.to_string()), + } +} + +#[test] +fn it_move_work() { + let mut test_file = PathBuf::from(TEST_FOLDER); + test_file.push("it_move_work"); + let mut test_file_out = test_file.clone(); + test_file.push("test.txt"); + test_file_out.push("out"); + test_file_out.push("test.txt"); + fs_extra::dir::create_all(&test_file.parent().unwrap(), true).unwrap(); + fs_extra::dir::create_all(&test_file_out.parent().unwrap(), true).unwrap(); + + write_all(&test_file, "test_data").unwrap(); + assert!(test_file.exists()); + assert!(!test_file_out.exists()); + let options = CopyOptions::new(); + let old_name = test_file.file_name(); + let old_content = read_to_string(&test_file).unwrap(); + move_file(&test_file, &test_file_out, &options).unwrap(); + assert!(!test_file.exists()); + assert!(test_file_out.exists()); + assert_eq!(old_name, test_file_out.file_name()); + let new_content = read_to_string(&test_file_out).unwrap(); + assert_eq!(old_content, new_content); +} + +#[test] +fn it_move_not_file() { + let mut test_file = PathBuf::from(TEST_FOLDER); + test_file.push("it_move_work"); + let mut test_file_out = test_file.clone(); + test_file.push("test.txt"); + test_file_out.push("out"); + test_file_out.push("test.txt"); + fs_extra::dir::create_all(&test_file.parent().unwrap(), true).unwrap(); + fs_extra::dir::create_all(&test_file_out.parent().unwrap(), true).unwrap(); + + write_all(&test_file, "test_data").unwrap(); + assert!(test_file.exists()); + assert!(!test_file_out.exists()); + test_file.pop(); + let options = CopyOptions::new(); + + match move_file(&test_file, &test_file_out, &options) { + Err(err) => match err.kind { + ErrorKind::InvalidFile => { + let wrong_path = format!("Path \"{}\" is not a file!", test_file.to_str().unwrap()); + assert_eq!(wrong_path, err.to_string()); + } + _ => { + panic!("wrong error"); + } + }, + Ok(_) => { + panic!("should be error"); + } + } +} + +#[test] +fn it_move_source_not_exist() { + let mut test_file = PathBuf::from(TEST_FOLDER); + test_file.push("it_move_source_not_exist"); + let mut test_file_out = test_file.clone(); + test_file.push("test1.txt"); + test_file_out.push("out"); + test_file_out.push("test.txt"); + fs_extra::dir::create_all(&test_file.parent().unwrap(), true).unwrap(); + fs_extra::dir::create_all(&test_file_out.parent().unwrap(), true).unwrap(); + + assert!(!test_file.exists()); + let options = CopyOptions::new(); + match move_file(&test_file, &test_file_out, &options) { + Ok(_) => panic!("should be error"), + Err(err) => match err.kind { + ErrorKind::NotFound => { + let wrong_path = format!( + "Path \"{}\" does not exist or you don't have \ + access!", + test_file.to_str().unwrap() + ); + + assert_eq!(wrong_path, err.to_string()); + () + } + _ => panic!("wrong error"), + }, + } +} + +#[test] +fn it_move_exist_overwrite() { + let mut test_file = PathBuf::from(TEST_FOLDER); + test_file.push("it_move_exist_overwrite"); + let mut test_file_out = test_file.clone(); + test_file.push("test.txt"); + test_file_out.push("out"); + test_file_out.push("test.txt"); + fs_extra::dir::create_all(&test_file.parent().unwrap(), true).unwrap(); + fs_extra::dir::create_all(&test_file_out.parent().unwrap(), true).unwrap(); + + write_all(&test_file, "test_data").unwrap(); + let mut options = CopyOptions::new(); + copy(&test_file, &test_file_out, &options).unwrap(); + assert!(test_file.exists()); + assert!(files_eq(&test_file, &test_file_out).unwrap()); + options.overwrite = true; + write_all(&test_file, "test_data2").unwrap(); + match move_file(&test_file, &test_file_out, &options) { + Ok(_) => { + assert!(!test_file.exists()); + assert_eq!(read_to_string(test_file_out).unwrap(), "test_data2"); + () + } + Err(err) => panic!(err.to_string()), + } +} + +#[test] +fn it_move_exist_not_overwrite() { + let mut test_file = PathBuf::from(TEST_FOLDER); + test_file.push("it_move_exist_not_overwrite"); + let mut test_file_out = test_file.clone(); + test_file.push("test.txt"); + test_file_out.push("out"); + test_file_out.push("test.txt"); + fs_extra::dir::create_all(&test_file.parent().unwrap(), true).unwrap(); + fs_extra::dir::create_all(&test_file_out.parent().unwrap(), true).unwrap(); + + write_all(&test_file, "test_data").unwrap(); + let mut options = CopyOptions::new(); + copy(&test_file, &test_file_out, &options).unwrap(); + assert!(test_file.exists()); + options.overwrite = false; + write_all(&test_file, "test_data2").unwrap(); + match move_file(&test_file, &test_file_out, &options) { + Ok(_) => panic!("should be error"), + Err(err) => { + let file_path = format!("Path \"{}\" exists", test_file_out.to_str().unwrap()); + + assert_eq!(file_path, err.to_string()); + assert!(!files_eq(test_file, test_file_out).unwrap()); + () + } + } +} + +#[test] +fn it_move_exist_skip_exist() { + let mut test_file = PathBuf::from(TEST_FOLDER); + test_file.push("it_move_exist_skip_exist"); + let mut test_file_out = test_file.clone(); + test_file.push("test.txt"); + test_file_out.push("out"); + test_file_out.push("test.txt"); + fs_extra::dir::create_all(&test_file.parent().unwrap(), true).unwrap(); + fs_extra::dir::create_all(&test_file_out.parent().unwrap(), true).unwrap(); + + write_all(&test_file, "test_data").unwrap(); + let mut options = CopyOptions::new(); + copy(&test_file, &test_file_out, &options).unwrap(); + assert!(test_file.exists()); + options.skip_exist = true; + write_all(&test_file, "test_data2").unwrap(); + match move_file(&test_file, &test_file_out, &options) { + Ok(_) => { + assert!(!files_eq(test_file, test_file_out).unwrap()); + () + } + Err(_) => panic!("should be error"), + } +} + +#[test] +fn it_move_exist_overwrite_and_skip_exist() { + let mut test_file = PathBuf::from(TEST_FOLDER); + test_file.push("it_move_exist_overwrite_and_skip_exist"); + let mut test_file_out = test_file.clone(); + test_file.push("test.txt"); + test_file_out.push("out"); + test_file_out.push("test.txt"); + fs_extra::dir::create_all(&test_file.parent().unwrap(), true).unwrap(); + fs_extra::dir::create_all(&test_file_out.parent().unwrap(), true).unwrap(); + + write_all(&test_file, "test_data").unwrap(); + let mut options = CopyOptions::new(); + copy(&test_file, &test_file_out, &options).unwrap(); + assert!(test_file.exists()); + assert!(files_eq(&test_file, &test_file_out).unwrap()); + options.overwrite = true; + options.skip_exist = true; + write_all(&test_file, "test_data2").unwrap(); + match move_file(&test_file, &test_file_out, &options) { + Ok(_) => { + assert!(!test_file.exists()); + assert_eq!(read_to_string(test_file_out).unwrap(), "test_data2"); + () + } + Err(err) => panic!(err.to_string()), + } +} + +#[test] +fn it_move_with_progress_work() { + let mut test_file = PathBuf::from(TEST_FOLDER); + test_file.push("it_move_with_progress_work"); + let mut test_file_out = test_file.clone(); + test_file.push("test.txt"); + test_file_out.push("out"); + test_file_out.push("test.txt"); + fs_extra::dir::create_all(&test_file.parent().unwrap(), true).unwrap(); + fs_extra::dir::create_all(&test_file_out.parent().unwrap(), true).unwrap(); + + write_all(&test_file, "test_data").unwrap(); + assert!(test_file.exists()); + assert!(!test_file_out.exists()); + let mut options = CopyOptions::new(); + options.buffer_size = 1; + let (tx, rx) = mpsc::channel(); + thread::spawn(move || { + let old_name = test_file.file_name(); + let old_content = read_to_string(&test_file).unwrap(); + let func_test = |process_info: TransitProcess| { + tx.send(process_info).unwrap(); + }; + move_file_with_progress(&test_file, &test_file_out, &options, func_test).unwrap(); + assert!(!test_file.exists()); + assert!(test_file_out.exists()); + assert_eq!(old_name, test_file_out.file_name()); + let new_content = read_to_string(&test_file_out).unwrap(); + assert_eq!(old_content, new_content); + }); + for i in 1..10 { + let process_info: TransitProcess = rx.recv().unwrap(); + assert_eq!(i, process_info.copied_bytes); + assert_eq!(9, process_info.total_bytes); + } +} + +#[test] +fn it_move_progress_not_file() { + let mut test_file = PathBuf::from(TEST_FOLDER); + test_file.push("it_move_progress_not_file"); + let mut test_file_out = test_file.clone(); + test_file.push("test.txt"); + test_file_out.push("out"); + test_file_out.push("test.txt"); + fs_extra::dir::create_all(&test_file.parent().unwrap(), true).unwrap(); + fs_extra::dir::create_all(&test_file_out.parent().unwrap(), true).unwrap(); + + write_all(&test_file, "test_data").unwrap(); + assert!(test_file.exists()); + assert!(!test_file_out.exists()); + test_file.pop(); + let options = CopyOptions::new(); + let func_test = |process_info: TransitProcess| println!("{}", process_info.total_bytes); + + match move_file_with_progress(&test_file, &test_file_out, &options, func_test) { + Err(err) => match err.kind { + ErrorKind::InvalidFile => { + let wrong_path = format!("Path \"{}\" is not a file!", test_file.to_str().unwrap()); + assert_eq!(wrong_path, err.to_string()); + } + _ => { + panic!("wrong error"); + } + }, + Ok(_) => { + panic!("should be error"); + } + } +} + +#[test] +fn it_move_with_progress_work_dif_buf_size() { + let mut test_file = PathBuf::from(TEST_FOLDER); + test_file.push("it_move_with_progress_work_dif_buf_size"); + let mut test_file_out = test_file.clone(); + test_file.push("test.txt"); + test_file_out.push("out"); + test_file_out.push("test.txt"); + fs_extra::dir::create_all(&test_file.parent().unwrap(), true).unwrap(); + fs_extra::dir::create_all(&test_file_out.parent().unwrap(), true).unwrap(); + + write_all(&test_file, "test_data_").unwrap(); + assert!(test_file.exists()); + assert!(!test_file_out.exists()); + let mut options = CopyOptions::new(); + options.buffer_size = 2; + let (tx, rx) = mpsc::channel(); + thread::spawn(move || { + let old_name = test_file.file_name(); + let old_content = read_to_string(&test_file).unwrap(); + let func_test = |process_info: TransitProcess| { + tx.send(process_info).unwrap(); + }; + move_file_with_progress(&test_file, &test_file_out, &options, func_test).unwrap(); + assert!(!test_file.exists()); + assert!(test_file_out.exists()); + assert_eq!(old_name, test_file_out.file_name()); + let new_content = read_to_string(&test_file_out).unwrap(); + assert_eq!(old_content, new_content); + }); + for i in 1..6 { + let process_info: TransitProcess = rx.recv().unwrap(); + assert_eq!(i * 2, process_info.copied_bytes); + assert_eq!(10, process_info.total_bytes); + } +} + +#[test] +fn it_move_with_progress_source_not_exist() { + let mut test_file = PathBuf::from(TEST_FOLDER); + test_file.push("it_move_with_progress_source_not_exist"); + let mut test_file_out = test_file.clone(); + test_file.push("test1.txt"); + test_file_out.push("out"); + test_file_out.push("test.txt"); + fs_extra::dir::create_all(&test_file.parent().unwrap(), true).unwrap(); + fs_extra::dir::create_all(&test_file_out.parent().unwrap(), true).unwrap(); + + assert!(!test_file.exists()); + let options = CopyOptions::new(); + let func_test = |process_info: TransitProcess| { + println!("{}", process_info.total_bytes); + }; + match move_file_with_progress(&test_file, &test_file_out, &options, func_test) { + Ok(_) => panic!("should be error"), + Err(err) => match err.kind { + ErrorKind::NotFound => { + let wrong_path = format!( + "Path \"{}\" does not exist or you don't have \ + access!", + test_file.to_str().unwrap() + ); + + assert_eq!(wrong_path, err.to_string()); + () + } + _ => panic!("wrong error"), + }, + } +} + +#[test] +fn it_move_with_progress_exist_overwrite() { + let mut test_file = PathBuf::from(TEST_FOLDER); + test_file.push("it_move_with_progress_exist_overwrite"); + let mut test_file_out = test_file.clone(); + test_file.push("test.txt"); + test_file_out.push("out"); + test_file_out.push("test.txt"); + fs_extra::dir::create_all(&test_file.parent().unwrap(), true).unwrap(); + fs_extra::dir::create_all(&test_file_out.parent().unwrap(), true).unwrap(); + + write_all(&test_file, "test_data").unwrap(); + let mut options = CopyOptions::new(); + copy(&test_file, &test_file_out, &options).unwrap(); + assert!(test_file.exists()); + assert!(files_eq(&test_file, &test_file_out).unwrap()); + options.overwrite = true; + write_all(&test_file, "test_data2").unwrap(); + let func_test = |process_info: TransitProcess| { + println!("{}", process_info.total_bytes); + }; + match move_file_with_progress(&test_file, &test_file_out, &options, func_test) { + Ok(_) => { + assert!(!test_file.exists()); + assert_eq!(read_to_string(test_file_out).unwrap(), "test_data2"); + () + } + Err(err) => panic!(err.to_string()), + } +} + +#[test] +fn it_move_with_progress_exist_not_overwrite() { + let mut test_file = PathBuf::from(TEST_FOLDER); + test_file.push("it_move_with_progress_exist_not_overwrite"); + let mut test_file_out = test_file.clone(); + test_file.push("test.txt"); + test_file_out.push("out"); + test_file_out.push("test.txt"); + fs_extra::dir::create_all(&test_file.parent().unwrap(), true).unwrap(); + fs_extra::dir::create_all(&test_file_out.parent().unwrap(), true).unwrap(); + + write_all(&test_file, "test_data").unwrap(); + let mut options = CopyOptions::new(); + copy(&test_file, &test_file_out, &options).unwrap(); + assert!(test_file.exists()); + options.overwrite = false; + write_all(&test_file, "test_data2").unwrap(); + let func_test = |process_info: TransitProcess| { + println!("{}", process_info.total_bytes); + }; + match move_file_with_progress(&test_file, &test_file_out, &options, func_test) { + Ok(_) => panic!("should be error"), + Err(err) => { + let file_path = format!("Path \"{}\" exists", test_file_out.to_str().unwrap()); + + assert_eq!(file_path, err.to_string()); + assert!(!files_eq(test_file, test_file_out).unwrap()); + () + } + } +} + +#[test] +fn it_move_with_progress_exist_skip_exist() { + let mut test_file = PathBuf::from(TEST_FOLDER); + test_file.push("it_move_with_progress_exist_skip_exist"); + let mut test_file_out = test_file.clone(); + test_file.push("test.txt"); + test_file_out.push("out"); + test_file_out.push("test.txt"); + fs_extra::dir::create_all(&test_file.parent().unwrap(), true).unwrap(); + fs_extra::dir::create_all(&test_file_out.parent().unwrap(), true).unwrap(); + + write_all(&test_file, "test_data").unwrap(); + let mut options = CopyOptions::new(); + copy(&test_file, &test_file_out, &options).unwrap(); + assert!(test_file.exists()); + options.skip_exist = true; + write_all(&test_file, "test_data2").unwrap(); + let func_test = |process_info: TransitProcess| { + println!("{}", process_info.total_bytes); + }; + match move_file_with_progress(&test_file, &test_file_out, &options, func_test) { + Ok(_) => { + assert!(!files_eq(test_file, test_file_out).unwrap()); + () + } + Err(_) => panic!("should be error"), + } +} + +#[test] +fn it_move_with_progress_exist_overwrite_and_skip_exist() { + let mut test_file = PathBuf::from(TEST_FOLDER); + test_file.push("it_move_with_progress_exist_overwrite_and_skip_exist"); + let mut test_file_out = test_file.clone(); + test_file.push("test.txt"); + test_file_out.push("out"); + test_file_out.push("test.txt"); + fs_extra::dir::create_all(&test_file.parent().unwrap(), true).unwrap(); + fs_extra::dir::create_all(&test_file_out.parent().unwrap(), true).unwrap(); + + write_all(&test_file, "test_data").unwrap(); + let mut options = CopyOptions::new(); + copy(&test_file, &test_file_out, &options).unwrap(); + assert!(test_file.exists()); + assert!(files_eq(&test_file, &test_file_out).unwrap()); + options.overwrite = true; + options.skip_exist = true; + write_all(&test_file, "test_data2").unwrap(); + let func_test = |process_info: TransitProcess| { + println!("{}", process_info.total_bytes); + }; + match move_file_with_progress(&test_file, &test_file_out, &options, func_test) { + Ok(_) => { + assert!(!test_file.exists()); + assert!(test_file_out.exists()); + assert_eq!(read_to_string(test_file_out).unwrap(), "test_data2"); + () + } + Err(err) => panic!(err.to_string()), + } +} diff --git a/vendor/fs_extra/tests/lib.rs b/vendor/fs_extra/tests/lib.rs new file mode 100644 index 000000000..2d8bfd024 --- /dev/null +++ b/vendor/fs_extra/tests/lib.rs @@ -0,0 +1,3883 @@ +use std::fs::read_dir; +use std::path::Path; +use std::sync::mpsc::{self, TryRecvError}; +use std::thread; + +extern crate fs_extra; +use fs_extra::error::*; +use fs_extra::*; + +fn files_eq(file1: P, file2: Q) -> bool +where + P: AsRef, + Q: AsRef, +{ + let content1 = fs_extra::file::read_to_string(file1).unwrap(); + let content2 = fs_extra::file::read_to_string(file2).unwrap(); + content1 == content2 +} + +fn compare_dir(path_from: P, path_to: Q) -> bool +where + P: AsRef, + Q: AsRef, +{ + let mut path_to = path_to.as_ref().to_path_buf(); + match path_from.as_ref().components().last() { + None => panic!("Invalid folder from"), + Some(dir_name) => { + path_to.push(dir_name.as_os_str()); + if !path_to.exists() { + return false; + } + } + } + + for entry in read_dir(&path_from).unwrap() { + let entry = entry.unwrap(); + let path = entry.path(); + if path.is_dir() { + if !compare_dir(path, &path_to) { + return false; + } + } else { + let mut path_to = path_to.to_path_buf(); + match path.file_name() { + None => panic!("No file name"), + Some(file_name) => { + path_to.push(file_name); + if !path_to.exists() { + return false; + } else if !files_eq(&path, path_to.clone()) { + return false; + } + } + } + } + } + + true +} + +const TEST_FOLDER: &'static str = "./tests/temp/lib"; + +#[test] +fn it_copy_work() { + let test_dir = Path::new(TEST_FOLDER).join("it_copy_work"); + let path_to = test_dir.join("out"); + let dir1 = (test_dir.join("dir1"), path_to.join("dir1")); + let dir2 = (test_dir.join("dir2"), path_to.join("dir2")); + let sub = (dir1.0.join("sub"), dir1.1.join("sub")); + let file1 = (test_dir.join("file1.txt"), path_to.join("file1.txt")); + let file2 = (test_dir.join("file2.txt"), path_to.join("file2.txt")); + let file3 = (dir1.0.join("file3.txt"), dir1.1.join("file3.txt")); + let file4 = (sub.0.join("file4.txt"), sub.1.join("file4.txt")); + let file5 = (dir2.0.join("file5.txt"), dir2.1.join("file5.txt")); + + match dir::create_all(&path_to, true) { + Ok(_) => {} + Err(_) => {} + }; + dir::create_all(&dir1.0, true).unwrap(); + dir::create_all(&dir2.0, true).unwrap(); + dir::create_all(&sub.0, true).unwrap(); + + assert!(dir1.0.exists()); + assert!(!dir1.1.exists()); + assert!(dir2.0.exists()); + assert!(!dir2.1.exists()); + assert!(sub.0.exists()); + assert!(!sub.1.exists()); + + file::write_all(&file1.0, "content1").unwrap(); + file::write_all(&file2.0, "content2").unwrap(); + file::write_all(&file3.0, "content3").unwrap(); + file::write_all(&file4.0, "content4").unwrap(); + file::write_all(&file5.0, "content5").unwrap(); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file3.0.exists()); + assert!(file4.0.exists()); + assert!(file5.0.exists()); + assert!(!file1.1.exists()); + assert!(!file2.1.exists()); + assert!(!file3.1.exists()); + assert!(!file4.1.exists()); + assert!(!file5.1.exists()); + + let mut from_paths = Vec::new(); + from_paths.push(dir1.0.as_path()); + from_paths.push(dir2.0.as_path()); + from_paths.push(file1.0.as_path()); + from_paths.push(file2.0.as_path()); + + let options = dir::CopyOptions::new(); + let result = copy_items(&from_paths, &path_to, &options).unwrap(); + + assert_eq!(40, result); + assert!(compare_dir(&dir1.0, &path_to)); + assert!(compare_dir(&dir2.0, &path_to)); + assert!(files_eq(&file1.0, &file1.1)); + assert!(files_eq(&file2.0, &file2.1)); +} + +#[test] +fn it_copy_source_not_exist() { + let test_dir = Path::new(TEST_FOLDER).join("it_copy_source_not_exist"); + let path_to = test_dir.join("out"); + let dir1 = (test_dir.join("dir1"), path_to.join("dir1")); + let dir2 = (test_dir.join("dir2"), path_to.join("dir2")); + let sub = (dir1.0.join("sub"), dir1.1.join("sub")); + let file1 = (test_dir.join("file1.txt"), path_to.join("file1.txt")); + + match dir::create_all(&path_to, true) { + Ok(_) => {} + Err(_) => {} + }; + + assert!(!dir1.0.exists()); + assert!(!dir1.1.exists()); + assert!(!dir2.0.exists()); + assert!(!dir2.1.exists()); + assert!(!sub.0.exists()); + assert!(!sub.1.exists()); + + assert!(!file1.0.exists()); + assert!(!file1.1.exists()); + + let mut from_paths = Vec::new(); + from_paths.push(dir1.0.as_path()); + from_paths.push(dir2.0.as_path()); + from_paths.push(file1.0.as_path()); + + let options = dir::CopyOptions::new(); + match copy_items(&from_paths, &path_to, &options) { + Ok(_) => panic!("Should be a error!"), + Err(err) => match err.kind { + ErrorKind::NotFound => {} + _ => {} + }, + }; +} + +#[test] +fn it_copy_exist_overwrite() { + let test_dir = Path::new(TEST_FOLDER).join("it_copy_exist_overwrite"); + let path_to = test_dir.join("out"); + let dir1 = (test_dir.join("dir1"), path_to.join("dir1")); + let dir2 = (test_dir.join("dir2"), path_to.join("dir2")); + let sub = (dir1.0.join("sub"), dir1.1.join("sub")); + let file1 = (test_dir.join("file1.txt"), path_to.join("file1.txt")); + let file2 = (test_dir.join("file2.txt"), path_to.join("file2.txt")); + let file3 = (dir1.0.join("file3.txt"), dir1.1.join("file3.txt")); + let file4 = (sub.0.join("file4.txt"), sub.1.join("file4.txt")); + let file5 = (dir2.0.join("file5.txt"), dir2.1.join("file5.txt")); + + match dir::create_all(&path_to, true) { + Ok(_) => {} + Err(_) => {} + }; + + dir::create_all(&dir1.0, true).unwrap(); + dir::create_all(&dir2.0, true).unwrap(); + dir::create_all(&sub.0, true).unwrap(); + dir::create_all(&sub.1, true).unwrap(); + + assert!(dir1.0.exists()); + assert!(dir1.1.exists()); + assert!(dir2.0.exists()); + assert!(!dir2.1.exists()); + assert!(sub.0.exists()); + assert!(sub.1.exists()); + + file::write_all(&file1.0, "content1").unwrap(); + file::write_all(&file2.0, "content2").unwrap(); + file::write_all(&file3.0, "content3").unwrap(); + file::write_all(&file4.0, "content4").unwrap(); + file::write_all(&file5.0, "content5").unwrap(); + + file::write_all(&file1.1, "old content1").unwrap(); + file::write_all(&file3.1, "old content3").unwrap(); + file::write_all(&file4.1, "old content4").unwrap(); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file3.0.exists()); + assert!(file4.0.exists()); + assert!(file5.0.exists()); + assert!(file1.1.exists()); + assert!(!file2.1.exists()); + assert!(file3.1.exists()); + assert!(file4.1.exists()); + assert!(!file5.1.exists()); + + let mut from_paths = Vec::new(); + from_paths.push(dir1.0.as_path()); + from_paths.push(dir2.0.as_path()); + from_paths.push(file1.0.as_path()); + from_paths.push(file2.0.as_path()); + + let mut options = dir::CopyOptions::new(); + options.overwrite = true; + let result = copy_items(&from_paths, &path_to, &options).unwrap(); + + assert_eq!(40, result); + assert!(compare_dir(&dir1.0, &path_to)); + assert!(compare_dir(&dir2.0, &path_to)); + assert!(files_eq(&file1.0, &file1.1)); + assert!(files_eq(&file2.0, &file2.1)); +} + +#[test] +fn it_copy_exist_not_overwrite() { + let test_dir = Path::new(TEST_FOLDER).join("it_copy_exist_not_overwrite"); + let path_to = test_dir.join("out"); + let dir1 = (test_dir.join("dir1"), path_to.join("dir1")); + let dir2 = (test_dir.join("dir2"), path_to.join("dir2")); + let sub = (dir1.0.join("sub"), dir1.1.join("sub")); + let file1 = (test_dir.join("file1.txt"), path_to.join("file1.txt")); + let file2 = (test_dir.join("file2.txt"), path_to.join("file2.txt")); + let file3 = (dir1.0.join("file3.txt"), dir1.1.join("file3.txt")); + let file4 = (sub.0.join("file4.txt"), sub.1.join("file4.txt")); + let file5 = (dir2.0.join("file5.txt"), dir2.1.join("file5.txt")); + + match dir::create_all(&path_to, true) { + Ok(_) => {} + Err(_) => {} + }; + + dir::create_all(&dir1.0, true).unwrap(); + dir::create_all(&dir2.0, true).unwrap(); + dir::create_all(&sub.0, true).unwrap(); + dir::create_all(&sub.1, true).unwrap(); + + assert!(dir1.0.exists()); + assert!(dir1.1.exists()); + assert!(dir2.0.exists()); + assert!(!dir2.1.exists()); + assert!(sub.0.exists()); + assert!(sub.1.exists()); + + file::write_all(&file1.0, "content1").unwrap(); + file::write_all(&file2.0, "content2").unwrap(); + file::write_all(&file3.0, "content3").unwrap(); + file::write_all(&file4.0, "content4").unwrap(); + file::write_all(&file5.0, "content5").unwrap(); + + file::write_all(&file1.1, "old content1").unwrap(); + file::write_all(&file3.1, "old content3").unwrap(); + file::write_all(&file4.1, "old content4").unwrap(); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file3.0.exists()); + assert!(file4.0.exists()); + assert!(file5.0.exists()); + assert!(file1.1.exists()); + assert!(!file2.1.exists()); + assert!(file3.1.exists()); + assert!(file4.1.exists()); + assert!(!file5.1.exists()); + + let mut from_paths = Vec::new(); + from_paths.push(dir1.0.as_path()); + from_paths.push(dir2.0.as_path()); + from_paths.push(file1.0.as_path()); + from_paths.push(file2.0.as_path()); + + let options = dir::CopyOptions::new(); + match copy_items(&from_paths, &path_to, &options) { + Ok(_) => panic!("Should be a error!"), + Err(err) => match err.kind { + ErrorKind::AlreadyExists => {} + _ => panic!(format!("{}", err.to_string())), + }, + }; +} + +#[test] +fn it_copy_exist_skip() { + let test_dir = Path::new(TEST_FOLDER).join("it_copy_exist_skip"); + let path_to = test_dir.join("out"); + let dir1 = (test_dir.join("dir1"), path_to.join("dir1")); + let dir2 = (test_dir.join("dir2"), path_to.join("dir2")); + let sub = (dir1.0.join("sub"), dir1.1.join("sub")); + let file1 = (test_dir.join("file1.txt"), path_to.join("file1.txt")); + let file2 = (test_dir.join("file2.txt"), path_to.join("file2.txt")); + let file3 = (dir1.0.join("file3.txt"), dir1.1.join("file3.txt")); + let file4 = (sub.0.join("file4.txt"), sub.1.join("file4.txt")); + let file5 = (dir2.0.join("file5.txt"), dir2.1.join("file5.txt")); + + match dir::create_all(&path_to, true) { + Ok(_) => {} + Err(_) => {} + }; + + dir::create_all(&dir1.0, true).unwrap(); + dir::create_all(&dir2.0, true).unwrap(); + dir::create_all(&sub.0, true).unwrap(); + dir::create_all(&sub.1, true).unwrap(); + + assert!(dir1.0.exists()); + assert!(dir1.1.exists()); + assert!(dir2.0.exists()); + assert!(!dir2.1.exists()); + assert!(sub.0.exists()); + assert!(sub.1.exists()); + + file::write_all(&file1.0, "content1").unwrap(); + file::write_all(&file2.0, "content2").unwrap(); + file::write_all(&file3.0, "content3").unwrap(); + file::write_all(&file4.0, "content4").unwrap(); + file::write_all(&file5.0, "content5").unwrap(); + + file::write_all(&file1.1, "old content1").unwrap(); + file::write_all(&file3.1, "old content3").unwrap(); + file::write_all(&file4.1, "old content4").unwrap(); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file3.0.exists()); + assert!(file4.0.exists()); + assert!(file5.0.exists()); + assert!(file1.1.exists()); + assert!(!file2.1.exists()); + assert!(file3.1.exists()); + assert!(file4.1.exists()); + assert!(!file5.1.exists()); + + let mut from_paths = Vec::new(); + from_paths.push(dir1.0.as_path()); + from_paths.push(dir2.0.as_path()); + from_paths.push(file1.0.as_path()); + from_paths.push(file2.0.as_path()); + + let mut options = dir::CopyOptions::new(); + options.skip_exist = true; + let result = copy_items(&from_paths, &path_to, &options).unwrap(); + + assert_eq!(16, result); + assert!(!compare_dir(&dir1.0, &path_to)); + assert!(compare_dir(&dir2.0, &path_to)); + assert!(!files_eq(&file1.0, &file1.1)); + assert!(files_eq(&file2.0, &file2.1)); +} + +#[test] +fn it_copy_exist_overwrite_and_skip_exist() { + let test_dir = Path::new(TEST_FOLDER).join("it_copy_exist_overwrite_and_skip_exist"); + let path_to = test_dir.join("out"); + let dir1 = (test_dir.join("dir1"), path_to.join("dir1")); + let dir2 = (test_dir.join("dir2"), path_to.join("dir2")); + let sub = (dir1.0.join("sub"), dir1.1.join("sub")); + let file1 = (test_dir.join("file1.txt"), path_to.join("file1.txt")); + let file2 = (test_dir.join("file2.txt"), path_to.join("file2.txt")); + let file3 = (dir1.0.join("file3.txt"), dir1.1.join("file3.txt")); + let file4 = (sub.0.join("file4.txt"), sub.1.join("file4.txt")); + let file5 = (dir2.0.join("file5.txt"), dir2.1.join("file5.txt")); + + match dir::create_all(&path_to, true) { + Ok(_) => {} + Err(_) => {} + }; + + dir::create_all(&dir1.0, true).unwrap(); + dir::create_all(&dir2.0, true).unwrap(); + dir::create_all(&sub.0, true).unwrap(); + dir::create_all(&sub.1, true).unwrap(); + + assert!(dir1.0.exists()); + assert!(dir1.1.exists()); + assert!(dir2.0.exists()); + assert!(!dir2.1.exists()); + assert!(sub.0.exists()); + assert!(sub.1.exists()); + + file::write_all(&file1.0, "content1").unwrap(); + file::write_all(&file2.0, "content2").unwrap(); + file::write_all(&file3.0, "content3").unwrap(); + file::write_all(&file4.0, "content4").unwrap(); + file::write_all(&file5.0, "content5").unwrap(); + + file::write_all(&file1.1, "old content1").unwrap(); + file::write_all(&file3.1, "old content3").unwrap(); + file::write_all(&file4.1, "old content4").unwrap(); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file3.0.exists()); + assert!(file4.0.exists()); + assert!(file5.0.exists()); + assert!(file1.1.exists()); + assert!(!file2.1.exists()); + assert!(file3.1.exists()); + assert!(file4.1.exists()); + assert!(!file5.1.exists()); + + let mut from_paths = Vec::new(); + from_paths.push(dir1.0.as_path()); + from_paths.push(dir2.0.as_path()); + from_paths.push(file1.0.as_path()); + from_paths.push(file2.0.as_path()); + + let mut options = dir::CopyOptions::new(); + options.overwrite = true; + options.skip_exist = true; + let result = copy_items(&from_paths, &path_to, &options).unwrap(); + + assert_eq!(40, result); + assert!(compare_dir(&dir1.0, &path_to)); + assert!(compare_dir(&dir2.0, &path_to)); + assert!(files_eq(&file1.0, &file1.1)); + assert!(files_eq(&file2.0, &file2.1)); +} + +#[test] +fn it_copy_using_first_levels() { + let test_dir = Path::new(TEST_FOLDER).join("it_copy_using_first_levels"); + let path_to = test_dir.join("out"); + let d_level_1 = (test_dir.join("d_level_1"), path_to.join("d_level_1")); + let d_level_2 = (d_level_1.0.join("d_level_2"), d_level_1.1.join("d_level_2")); + let d_level_3 = (d_level_2.0.join("d_level_3"), d_level_2.1.join("d_level_3")); + let d_level_4 = (d_level_3.0.join("d_level_4"), d_level_3.1.join("d_level_4")); + let d_level_5 = (d_level_4.0.join("d_level_5"), d_level_4.1.join("d_level_5")); + + let d2_level_1 = (test_dir.join("d2_level_1"), path_to.join("d2_level_1")); + let d2_level_2 = ( + d_level_1.0.join("d2_level_2"), + d_level_1.1.join("d2_level_2"), + ); + let d2_level_3 = ( + d_level_2.0.join("d2_level_3"), + d_level_2.1.join("d2_level_3"), + ); + let d2_level_4 = ( + d_level_3.0.join("d2_level_4"), + d_level_3.1.join("d2_level_4"), + ); + let d2_level_5 = ( + d_level_4.0.join("d2_level_5"), + d_level_4.1.join("d2_level_5"), + ); + + let d3_level_1 = (test_dir.join("d3_level_1"), path_to.join("d3_level_1")); + + let file1 = (d_level_1.0.join("file1.txt"), d_level_1.1.join("file1.txt")); + let file2 = (d_level_2.0.join("file2.txt"), d_level_2.1.join("file2.txt")); + let file3 = (d_level_3.0.join("file3.txt"), d_level_3.1.join("file3.txt")); + let file4 = (d_level_4.0.join("file4.txt"), d_level_4.1.join("file4.txt")); + let file5 = (d_level_5.0.join("file5.txt"), d_level_5.1.join("file5.txt")); + + let file21 = ( + d2_level_1.0.join("file21.txt"), + d2_level_1.1.join("file21.txt"), + ); + let file22 = ( + d2_level_2.0.join("file22.txt"), + d2_level_2.1.join("file22.txt"), + ); + let file23 = ( + d2_level_3.0.join("file23.txt"), + d2_level_3.1.join("file23.txt"), + ); + let file24 = ( + d2_level_4.0.join("file24.txt"), + d2_level_4.1.join("file24.txt"), + ); + let file25 = ( + d2_level_5.0.join("file25.txt"), + d2_level_5.1.join("file25.txt"), + ); + + let file31 = ( + d3_level_1.0.join("file31.txt"), + d3_level_1.1.join("file31.txt"), + ); + + dir::create_all(&d_level_1.0, true).unwrap(); + dir::create_all(&d_level_2.0, true).unwrap(); + dir::create_all(&d_level_3.0, true).unwrap(); + dir::create_all(&d_level_4.0, true).unwrap(); + dir::create_all(&d_level_5.0, true).unwrap(); + dir::create_all(&path_to, true).unwrap(); + + dir::create_all(&d2_level_1.0, true).unwrap(); + dir::create_all(&d2_level_2.0, true).unwrap(); + dir::create_all(&d2_level_3.0, true).unwrap(); + dir::create_all(&d2_level_4.0, true).unwrap(); + dir::create_all(&d2_level_5.0, true).unwrap(); + + dir::create_all(&d3_level_1.0, true).unwrap(); + + assert!(path_to.exists()); + assert!(d_level_1.0.exists()); + assert!(d_level_2.0.exists()); + assert!(d_level_3.0.exists()); + assert!(d_level_4.0.exists()); + assert!(d_level_5.0.exists()); + + assert!(d2_level_1.0.exists()); + assert!(d2_level_2.0.exists()); + assert!(d2_level_3.0.exists()); + assert!(d2_level_4.0.exists()); + assert!(d2_level_5.0.exists()); + + assert!(d3_level_1.0.exists()); + + assert!(!d_level_1.1.exists()); + assert!(!d_level_2.1.exists()); + assert!(!d_level_3.1.exists()); + assert!(!d_level_4.1.exists()); + assert!(!d_level_5.1.exists()); + + assert!(!d2_level_1.1.exists()); + assert!(!d2_level_2.1.exists()); + assert!(!d2_level_3.1.exists()); + assert!(!d2_level_4.1.exists()); + assert!(!d2_level_5.1.exists()); + + assert!(!d3_level_1.1.exists()); + + fs_extra::file::write_all(&file1.0, "content1").unwrap(); + fs_extra::file::write_all(&file2.0, "content2").unwrap(); + fs_extra::file::write_all(&file3.0, "content3").unwrap(); + fs_extra::file::write_all(&file4.0, "content4").unwrap(); + fs_extra::file::write_all(&file5.0, "content5").unwrap(); + + fs_extra::file::write_all(&file21.0, "2content1").unwrap(); + fs_extra::file::write_all(&file22.0, "2content2").unwrap(); + fs_extra::file::write_all(&file23.0, "2content3").unwrap(); + fs_extra::file::write_all(&file24.0, "2content4").unwrap(); + fs_extra::file::write_all(&file25.0, "2content5").unwrap(); + + fs_extra::file::write_all(&file31.0, "3content1").unwrap(); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file3.0.exists()); + assert!(file4.0.exists()); + assert!(file5.0.exists()); + + assert!(file21.0.exists()); + assert!(file22.0.exists()); + assert!(file23.0.exists()); + assert!(file24.0.exists()); + assert!(file25.0.exists()); + + assert!(file31.0.exists()); + + assert!(!file1.1.exists()); + assert!(!file2.1.exists()); + assert!(!file3.1.exists()); + assert!(!file4.1.exists()); + assert!(!file5.1.exists()); + + assert!(!file21.1.exists()); + assert!(!file22.1.exists()); + assert!(!file23.1.exists()); + assert!(!file24.1.exists()); + assert!(!file25.1.exists()); + + assert!(!file31.1.exists()); + + let mut from_paths = Vec::new(); + from_paths.push(d_level_1.0.as_path()); + from_paths.push(d2_level_1.0.as_path()); + from_paths.push(d3_level_1.0.as_path()); + + let mut options = dir::CopyOptions::new(); + options.depth = 1; + let result = copy_items(&from_paths, path_to, &options).unwrap(); + + assert_eq!(26, result); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file3.0.exists()); + assert!(file4.0.exists()); + assert!(file5.0.exists()); + + assert!(file21.0.exists()); + assert!(file22.0.exists()); + assert!(file23.0.exists()); + assert!(file24.0.exists()); + assert!(file25.0.exists()); + + assert!(file31.0.exists()); + + assert!(file1.1.exists()); + assert!(!file2.1.exists()); + assert!(!file3.1.exists()); + assert!(!file4.1.exists()); + assert!(!file5.1.exists()); + + assert!(file21.1.exists()); + assert!(!file22.1.exists()); + assert!(!file23.1.exists()); + assert!(!file24.1.exists()); + assert!(!file25.1.exists()); + + assert!(file31.1.exists()); + assert!(files_eq(&file1.0, &file1.1)); + assert!(files_eq(&file21.0, &file21.1)); + assert!(files_eq(&file31.0, &file31.1)); +} + +#[test] +fn it_copy_using_four_levels() { + let test_dir = Path::new(TEST_FOLDER).join("it_copy_using_four_levels"); + let path_to = test_dir.join("out"); + let d_level_1 = (test_dir.join("d_level_1"), path_to.join("d_level_1")); + let d_level_2 = (d_level_1.0.join("d_level_2"), d_level_1.1.join("d_level_2")); + let d_level_3 = (d_level_2.0.join("d_level_3"), d_level_2.1.join("d_level_3")); + let d_level_4 = (d_level_3.0.join("d_level_4"), d_level_3.1.join("d_level_4")); + let d_level_5 = (d_level_4.0.join("d_level_5"), d_level_4.1.join("d_level_5")); + + let d2_level_1 = (test_dir.join("d2_level_1"), path_to.join("d2_level_1")); + let d2_level_2 = ( + d_level_1.0.join("d2_level_2"), + d_level_1.1.join("d2_level_2"), + ); + let d2_level_3 = ( + d_level_2.0.join("d2_level_3"), + d_level_2.1.join("d2_level_3"), + ); + let d2_level_4 = ( + d_level_3.0.join("d2_level_4"), + d_level_3.1.join("d2_level_4"), + ); + let d2_level_5 = ( + d_level_4.0.join("d2_level_5"), + d_level_4.1.join("d2_level_5"), + ); + + let d3_level_1 = (test_dir.join("d3_level_1"), path_to.join("d3_level_1")); + + let file1 = (d_level_1.0.join("file1.txt"), d_level_1.1.join("file1.txt")); + let file2 = (d_level_2.0.join("file2.txt"), d_level_2.1.join("file2.txt")); + let file3 = (d_level_3.0.join("file3.txt"), d_level_3.1.join("file3.txt")); + let file4 = (d_level_4.0.join("file4.txt"), d_level_4.1.join("file4.txt")); + let file5 = (d_level_5.0.join("file5.txt"), d_level_5.1.join("file5.txt")); + + let file21 = ( + d2_level_1.0.join("file21.txt"), + d2_level_1.1.join("file21.txt"), + ); + let file22 = ( + d2_level_2.0.join("file22.txt"), + d2_level_2.1.join("file22.txt"), + ); + let file23 = ( + d2_level_3.0.join("file23.txt"), + d2_level_3.1.join("file23.txt"), + ); + let file24 = ( + d2_level_4.0.join("file24.txt"), + d2_level_4.1.join("file24.txt"), + ); + let file25 = ( + d2_level_5.0.join("file25.txt"), + d2_level_5.1.join("file25.txt"), + ); + + let file31 = ( + d3_level_1.0.join("file31.txt"), + d3_level_1.1.join("file31.txt"), + ); + + dir::create_all(&d_level_1.0, true).unwrap(); + dir::create_all(&d_level_2.0, true).unwrap(); + dir::create_all(&d_level_3.0, true).unwrap(); + dir::create_all(&d_level_4.0, true).unwrap(); + dir::create_all(&d_level_5.0, true).unwrap(); + dir::create_all(&path_to, true).unwrap(); + + dir::create_all(&d2_level_1.0, true).unwrap(); + dir::create_all(&d2_level_2.0, true).unwrap(); + dir::create_all(&d2_level_3.0, true).unwrap(); + dir::create_all(&d2_level_4.0, true).unwrap(); + dir::create_all(&d2_level_5.0, true).unwrap(); + + dir::create_all(&d3_level_1.0, true).unwrap(); + + assert!(path_to.exists()); + assert!(d_level_1.0.exists()); + assert!(d_level_2.0.exists()); + assert!(d_level_3.0.exists()); + assert!(d_level_4.0.exists()); + assert!(d_level_5.0.exists()); + + assert!(d2_level_1.0.exists()); + assert!(d2_level_2.0.exists()); + assert!(d2_level_3.0.exists()); + assert!(d2_level_4.0.exists()); + assert!(d2_level_5.0.exists()); + + assert!(d3_level_1.0.exists()); + + assert!(!d_level_1.1.exists()); + assert!(!d_level_2.1.exists()); + assert!(!d_level_3.1.exists()); + assert!(!d_level_4.1.exists()); + assert!(!d_level_5.1.exists()); + + assert!(!d2_level_1.1.exists()); + assert!(!d2_level_2.1.exists()); + assert!(!d2_level_3.1.exists()); + assert!(!d2_level_4.1.exists()); + assert!(!d2_level_5.1.exists()); + + assert!(!d3_level_1.1.exists()); + + fs_extra::file::write_all(&file1.0, "content1").unwrap(); + fs_extra::file::write_all(&file2.0, "content2").unwrap(); + fs_extra::file::write_all(&file3.0, "content3").unwrap(); + fs_extra::file::write_all(&file4.0, "content4").unwrap(); + fs_extra::file::write_all(&file5.0, "content5").unwrap(); + + fs_extra::file::write_all(&file21.0, "2content1").unwrap(); + fs_extra::file::write_all(&file22.0, "2content2").unwrap(); + fs_extra::file::write_all(&file23.0, "2content3").unwrap(); + fs_extra::file::write_all(&file24.0, "2content4").unwrap(); + fs_extra::file::write_all(&file25.0, "2content5").unwrap(); + + fs_extra::file::write_all(&file31.0, "3content1").unwrap(); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file3.0.exists()); + assert!(file4.0.exists()); + assert!(file5.0.exists()); + + assert!(file21.0.exists()); + assert!(file22.0.exists()); + assert!(file23.0.exists()); + assert!(file24.0.exists()); + assert!(file25.0.exists()); + + assert!(file31.0.exists()); + + assert!(!file1.1.exists()); + assert!(!file2.1.exists()); + assert!(!file3.1.exists()); + assert!(!file4.1.exists()); + assert!(!file5.1.exists()); + + assert!(!file21.1.exists()); + assert!(!file22.1.exists()); + assert!(!file23.1.exists()); + assert!(!file24.1.exists()); + assert!(!file25.1.exists()); + + assert!(!file31.1.exists()); + + let mut from_paths = Vec::new(); + from_paths.push(d_level_1.0.as_path()); + from_paths.push(d2_level_1.0.as_path()); + from_paths.push(d3_level_1.0.as_path()); + + let mut options = dir::CopyOptions::new(); + options.depth = 4; + let result = copy_items(&from_paths, path_to, &options).unwrap(); + + assert_eq!(77, result); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file3.0.exists()); + assert!(file4.0.exists()); + assert!(file5.0.exists()); + + assert!(file21.0.exists()); + assert!(file22.0.exists()); + assert!(file23.0.exists()); + assert!(file24.0.exists()); + assert!(file25.0.exists()); + + assert!(file31.0.exists()); + + assert!(file1.1.exists()); + assert!(file2.1.exists()); + assert!(file3.1.exists()); + assert!(file4.1.exists()); + assert!(!file5.1.exists()); + + assert!(file21.1.exists()); + assert!(file22.1.exists()); + assert!(file23.1.exists()); + assert!(file24.1.exists()); + assert!(!file25.1.exists()); + + assert!(file31.1.exists()); + assert!(files_eq(&file1.0, &file1.1)); + assert!(files_eq(&file21.0, &file21.1)); + assert!(files_eq(&file31.0, &file31.1)); +} +#[test] + +fn it_copy_content_only_opton() { + let test_dir = Path::new(TEST_FOLDER).join("it_copy_content_only_opton"); + let path_to = test_dir.join("out"); + + let file1 = (test_dir.join("file1.txt"), path_to.join("file1.txt")); + + let mut options = dir::CopyOptions::new(); + options.content_only = true; + match copy_items(&vec![&file1.0], &file1.1, &options) { + Err(err) => match err.kind { + ErrorKind::Other => { + assert_eq!(1, 1); + } + _ => { + panic!(format!("wrong error {}", err.to_string())); + } + }, + Ok(_) => { + panic!("should be error"); + } + } +} + +#[test] +fn it_copy_progress_work() { + let test_dir = Path::new(TEST_FOLDER).join("it_copy_progress_work"); + let path_to = test_dir.join("out"); + let dir1 = (test_dir.join("dir1"), path_to.join("dir1")); + let dir2 = (test_dir.join("dir2"), path_to.join("dir2")); + let sub = (dir1.0.join("sub"), dir1.1.join("sub")); + let file1 = (test_dir.join("file1.txt"), path_to.join("file1.txt")); + let file2 = (test_dir.join("file2.txt"), path_to.join("file2.txt")); + let file3 = (dir1.0.join("file3.txt"), dir1.1.join("file3.txt")); + let file4 = (sub.0.join("file4.txt"), sub.1.join("file4.txt")); + let file5 = (dir2.0.join("file5.txt"), dir2.1.join("file5.txt")); + + match dir::create_all(&path_to, true) { + Ok(_) => {} + Err(_) => {} + }; + dir::create_all(&dir1.0, true).unwrap(); + dir::create_all(&dir2.0, true).unwrap(); + dir::create_all(&sub.0, true).unwrap(); + + assert!(dir1.0.exists()); + assert!(!dir1.1.exists()); + assert!(dir2.0.exists()); + assert!(!dir2.1.exists()); + assert!(sub.0.exists()); + assert!(!sub.1.exists()); + + file::write_all(&file1.0, "content1").unwrap(); + file::write_all(&file2.0, "content22").unwrap(); + file::write_all(&file3.0, "content3").unwrap(); + file::write_all(&file4.0, "content4").unwrap(); + file::write_all(&file5.0, "content5").unwrap(); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file3.0.exists()); + assert!(file4.0.exists()); + assert!(file5.0.exists()); + assert!(!file1.1.exists()); + assert!(!file2.1.exists()); + assert!(!file3.1.exists()); + assert!(!file4.1.exists()); + assert!(!file5.1.exists()); + + let options = dir::CopyOptions::new(); + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let mut from_paths = Vec::new(); + from_paths.push(dir1.0.as_path()); + from_paths.push(dir2.0.as_path()); + from_paths.push(file1.0.as_path()); + from_paths.push(file2.0.as_path()); + + let func_test = |process_info: TransitProcess| { + tx.send(process_info).unwrap(); + dir::TransitProcessResult::ContinueOrAbort + }; + let result = copy_items_with_progress(&from_paths, &path_to, &options, func_test).unwrap(); + + assert_eq!(41, result); + assert!(compare_dir(&dir1.0, &path_to)); + assert!(compare_dir(&dir2.0, &path_to)); + assert!(files_eq(&file1.0, &file1.1)); + assert!(files_eq(&file2.0, &file2.1)); + }) + .join(); + + loop { + match rx.try_recv() { + Ok(process_info) => { + if process_info.file_name == "file2.txt" { + assert_eq!(9, process_info.file_total_bytes); + assert_eq!(41, process_info.total_bytes); + } else if process_info.file_name == "file1.txt" { + assert_eq!(8, process_info.file_total_bytes); + assert_eq!(41, process_info.total_bytes); + } + } + Err(TryRecvError::Disconnected) => { + break; + } + Err(TryRecvError::Empty) => {} + } + } + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } +} + +#[test] +fn it_copy_with_progress_work_dif_buf_size() { + let test_dir = Path::new(TEST_FOLDER).join("it_copy_with_progress_work_dif_buf_size"); + let path_to = test_dir.join("out"); + let dir1 = (test_dir.join("dir1"), path_to.join("dir1")); + let dir2 = (test_dir.join("dir2"), path_to.join("dir2")); + let sub = (dir1.0.join("sub"), dir1.1.join("sub")); + let file1 = (test_dir.join("file1.txt"), path_to.join("file1.txt")); + let file2 = (test_dir.join("file2.txt"), path_to.join("file2.txt")); + let file3 = (dir1.0.join("file3.txt"), dir1.1.join("file3.txt")); + let file4 = (sub.0.join("file4.txt"), sub.1.join("file4.txt")); + let file5 = (dir2.0.join("file5.txt"), dir2.1.join("file5.txt")); + + match dir::create_all(&path_to, true) { + Ok(_) => {} + Err(_) => {} + }; + dir::create_all(&dir1.0, true).unwrap(); + dir::create_all(&dir2.0, true).unwrap(); + dir::create_all(&sub.0, true).unwrap(); + + assert!(dir1.0.exists()); + assert!(!dir1.1.exists()); + assert!(dir2.0.exists()); + assert!(!dir2.1.exists()); + assert!(sub.0.exists()); + assert!(!sub.1.exists()); + + file::write_all(&file1.0, "content1").unwrap(); + file::write_all(&file2.0, "content2").unwrap(); + file::write_all(&file3.0, "content3").unwrap(); + file::write_all(&file4.0, "content4").unwrap(); + file::write_all(&file5.0, "content5").unwrap(); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file3.0.exists()); + assert!(file4.0.exists()); + assert!(file5.0.exists()); + assert!(!file1.1.exists()); + assert!(!file2.1.exists()); + assert!(!file3.1.exists()); + assert!(!file4.1.exists()); + assert!(!file5.1.exists()); + + let mut options = dir::CopyOptions::new(); + options.buffer_size = 1; + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let mut from_paths = Vec::new(); + from_paths.push(file1.0.as_path().to_str().unwrap().to_string()); + from_paths.push(file2.0.as_path().to_str().unwrap().to_string()); + from_paths.push(dir1.0.as_path().to_str().unwrap().to_string()); + from_paths.push(dir2.0.as_path().to_str().unwrap().to_string()); + + let func_test = |process_info: TransitProcess| { + tx.send(process_info).unwrap(); + dir::TransitProcessResult::ContinueOrAbort + }; + + let result = copy_items_with_progress(&from_paths, &path_to, &options, func_test).unwrap(); + + assert_eq!(40, result); + assert!(compare_dir(&dir1.0, &path_to)); + assert!(compare_dir(&dir2.0, &path_to)); + assert!(files_eq(&file1.0, &file1.1)); + assert!(files_eq(&file2.0, &file2.1)); + + let mut options = dir::CopyOptions::new(); + options.buffer_size = 2; + options.overwrite = true; + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let func_test = |process_info: TransitProcess| { + tx.send(process_info).unwrap(); + dir::TransitProcessResult::ContinueOrAbort + }; + let result = + copy_items_with_progress(&from_paths, &path_to, &options, func_test).unwrap(); + + assert_eq!(40, result); + assert!(compare_dir(&dir1.0, &path_to)); + assert!(compare_dir(&dir2.0, &path_to)); + assert!(files_eq(&file1.0, &file1.1)); + assert!(files_eq(&file2.0, &file2.1)); + }) + .join(); + for i in 1..5 { + let process_info: TransitProcess = rx.recv().unwrap(); + assert_eq!(i * 2, process_info.file_bytes_copied); + assert_eq!(i * 2, process_info.copied_bytes); + assert_eq!(8, process_info.file_total_bytes); + assert_eq!(40, process_info.total_bytes); + } + for i in 1..5 { + let process_info: TransitProcess = rx.recv().unwrap(); + assert_eq!(i * 2 + 8, process_info.copied_bytes); + assert_eq!(i * 2, process_info.file_bytes_copied); + assert_eq!(8, process_info.file_total_bytes); + assert_eq!(40, process_info.total_bytes); + } + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } + }) + .join(); + + for i in 1..9 { + let process_info: TransitProcess = rx.recv().unwrap(); + assert_eq!(i, process_info.file_bytes_copied); + assert_eq!(i, process_info.copied_bytes); + assert_eq!(8, process_info.file_total_bytes); + assert_eq!(40, process_info.total_bytes); + } + for i in 1..9 { + let process_info: TransitProcess = rx.recv().unwrap(); + assert_eq!(i + 8, process_info.copied_bytes); + assert_eq!(i, process_info.file_bytes_copied); + assert_eq!(8, process_info.file_total_bytes); + assert_eq!(40, process_info.total_bytes); + } + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } +} + +#[test] +fn it_copy_with_progress_source_not_exist() { + let test_dir = Path::new(TEST_FOLDER).join("it_copy_with_progress_source_not_exist"); + let path_to = test_dir.join("out"); + let dir1 = (test_dir.join("dir1"), path_to.join("dir1")); + let dir2 = (test_dir.join("dir2"), path_to.join("dir2")); + let sub = (dir1.0.join("sub"), dir1.1.join("sub")); + let file1 = (test_dir.join("file1.txt"), path_to.join("file1.txt")); + + match dir::create_all(&path_to, true) { + Ok(_) => {} + Err(_) => {} + }; + + assert!(!dir1.0.exists()); + assert!(!dir1.1.exists()); + assert!(!dir2.0.exists()); + assert!(!dir2.1.exists()); + assert!(!sub.0.exists()); + assert!(!sub.1.exists()); + + assert!(!file1.0.exists()); + assert!(!file1.1.exists()); + + let mut from_paths = Vec::new(); + from_paths.push(dir1.0.as_path()); + from_paths.push(dir2.0.as_path()); + from_paths.push(file1.0.as_path()); + + let func_test = |process_info: TransitProcess| { + println!("{}", process_info.total_bytes); + dir::TransitProcessResult::ContinueOrAbort + }; + + let options = dir::CopyOptions::new(); + match copy_items_with_progress(&from_paths, &path_to, &options, func_test) { + Ok(_) => panic!("Should be a error!"), + Err(err) => match err.kind { + ErrorKind::NotFound => {} + _ => {} + }, + }; +} + +#[test] +fn it_copy_with_progress_exist_overwrite() { + let test_dir = Path::new(TEST_FOLDER).join("it_copy_with_progress_exist_overwrite"); + let path_to = test_dir.join("out"); + let dir1 = (test_dir.join("dir1"), path_to.join("dir1")); + let dir2 = (test_dir.join("dir2"), path_to.join("dir2")); + let sub = (dir1.0.join("sub"), dir1.1.join("sub")); + let file1 = (test_dir.join("file1.txt"), path_to.join("file1.txt")); + let file2 = (test_dir.join("file2.txt"), path_to.join("file2.txt")); + let file3 = (dir1.0.join("file3.txt"), dir1.1.join("file3.txt")); + let file4 = (sub.0.join("file4.txt"), sub.1.join("file4.txt")); + let file5 = (dir2.0.join("file5.txt"), dir2.1.join("file5.txt")); + + match dir::create_all(&path_to, true) { + Ok(_) => {} + Err(_) => {} + }; + + dir::create_all(&dir1.0, true).unwrap(); + dir::create_all(&dir2.0, true).unwrap(); + dir::create_all(&sub.0, true).unwrap(); + dir::create_all(&sub.1, true).unwrap(); + + assert!(dir1.0.exists()); + assert!(dir1.1.exists()); + assert!(dir2.0.exists()); + assert!(!dir2.1.exists()); + assert!(sub.0.exists()); + assert!(sub.1.exists()); + + file::write_all(&file1.0, "content1").unwrap(); + file::write_all(&file2.0, "content2").unwrap(); + file::write_all(&file3.0, "content3").unwrap(); + file::write_all(&file4.0, "content4").unwrap(); + file::write_all(&file5.0, "content5").unwrap(); + + file::write_all(&file1.1, "old content1").unwrap(); + file::write_all(&file3.1, "old content3").unwrap(); + file::write_all(&file4.1, "old content4").unwrap(); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file3.0.exists()); + assert!(file4.0.exists()); + assert!(file5.0.exists()); + assert!(file1.1.exists()); + assert!(!file2.1.exists()); + assert!(file3.1.exists()); + assert!(file4.1.exists()); + assert!(!file5.1.exists()); + + let mut options = dir::CopyOptions::new(); + options.overwrite = true; + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let mut from_paths = Vec::new(); + from_paths.push(dir1.0.as_path()); + from_paths.push(dir2.0.as_path()); + from_paths.push(file1.0.as_path()); + from_paths.push(file2.0.as_path()); + + let func_test = |process_info: TransitProcess| { + tx.send(process_info).unwrap(); + dir::TransitProcessResult::ContinueOrAbort + }; + + let result = copy_items_with_progress(&from_paths, &path_to, &options, func_test).unwrap(); + + assert_eq!(40, result); + assert!(compare_dir(&dir1.0, &path_to)); + assert!(compare_dir(&dir2.0, &path_to)); + assert!(files_eq(&file1.0, &file1.1)); + assert!(files_eq(&file2.0, &file2.1)); + }) + .join(); + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } + + match rx.recv() { + Err(_) => panic!("Errors should not be!"), + _ => {} + } +} + +#[test] +fn it_copy_with_progress_exist_not_overwrite() { + let test_dir = Path::new(TEST_FOLDER).join("it_copy_with_progress_exist_not_overwrite"); + let path_to = test_dir.join("out"); + let dir1 = (test_dir.join("dir1"), path_to.join("dir1")); + let dir2 = (test_dir.join("dir2"), path_to.join("dir2")); + let sub = (dir1.0.join("sub"), dir1.1.join("sub")); + let file1 = (test_dir.join("file1.txt"), path_to.join("file1.txt")); + let file2 = (test_dir.join("file2.txt"), path_to.join("file2.txt")); + let file3 = (dir1.0.join("file3.txt"), dir1.1.join("file3.txt")); + let file4 = (sub.0.join("file4.txt"), sub.1.join("file4.txt")); + let file5 = (dir2.0.join("file5.txt"), dir2.1.join("file5.txt")); + + match dir::create_all(&path_to, true) { + Ok(_) => {} + Err(_) => {} + }; + + dir::create_all(&dir1.0, true).unwrap(); + dir::create_all(&dir2.0, true).unwrap(); + dir::create_all(&sub.0, true).unwrap(); + dir::create_all(&sub.1, true).unwrap(); + + assert!(dir1.0.exists()); + assert!(dir1.1.exists()); + assert!(dir2.0.exists()); + assert!(!dir2.1.exists()); + assert!(sub.0.exists()); + assert!(sub.1.exists()); + + file::write_all(&file1.0, "content1").unwrap(); + file::write_all(&file2.0, "content2").unwrap(); + file::write_all(&file3.0, "content3").unwrap(); + file::write_all(&file4.0, "content4").unwrap(); + file::write_all(&file5.0, "content5").unwrap(); + + file::write_all(&file1.1, "old content1").unwrap(); + file::write_all(&file3.1, "old content3").unwrap(); + file::write_all(&file4.1, "old content4").unwrap(); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file3.0.exists()); + assert!(file4.0.exists()); + assert!(file5.0.exists()); + assert!(file1.1.exists()); + assert!(!file2.1.exists()); + assert!(file3.1.exists()); + assert!(file4.1.exists()); + assert!(!file5.1.exists()); + + let mut from_paths = Vec::new(); + from_paths.push(dir1.0.as_path()); + from_paths.push(dir2.0.as_path()); + from_paths.push(file1.0.as_path()); + from_paths.push(file2.0.as_path()); + + let options = dir::CopyOptions::new(); + let func_test = |process_info: TransitProcess| { + println!("{}", process_info.total_bytes); + dir::TransitProcessResult::ContinueOrAbort + }; + + match copy_items_with_progress(&from_paths, &path_to, &options, func_test) { + Ok(_) => panic!("Should be a error!"), + Err(err) => match err.kind { + ErrorKind::AlreadyExists => {} + _ => panic!(format!("{}", err.to_string())), + }, + }; +} + +#[test] +fn it_copy_with_progress_exist_skip_exist() { + let test_dir = Path::new(TEST_FOLDER).join("it_copy_with_progress_exist_skip_exist"); + let path_to = test_dir.join("out"); + let dir1 = (test_dir.join("dir1"), path_to.join("dir1")); + let dir2 = (test_dir.join("dir2"), path_to.join("dir2")); + let sub = (dir1.0.join("sub"), dir1.1.join("sub")); + let file1 = (test_dir.join("file1.txt"), path_to.join("file1.txt")); + let file2 = (test_dir.join("file2.txt"), path_to.join("file2.txt")); + let file3 = (dir1.0.join("file3.txt"), dir1.1.join("file3.txt")); + let file4 = (sub.0.join("file4.txt"), sub.1.join("file4.txt")); + let file5 = (dir2.0.join("file5.txt"), dir2.1.join("file5.txt")); + + match dir::create_all(&path_to, true) { + Ok(_) => {} + Err(_) => {} + }; + + dir::create_all(&dir1.0, true).unwrap(); + dir::create_all(&dir2.0, true).unwrap(); + dir::create_all(&sub.0, true).unwrap(); + dir::create_all(&sub.1, true).unwrap(); + + assert!(dir1.0.exists()); + assert!(dir1.1.exists()); + assert!(dir2.0.exists()); + assert!(!dir2.1.exists()); + assert!(sub.0.exists()); + assert!(sub.1.exists()); + + file::write_all(&file1.0, "content1").unwrap(); + file::write_all(&file2.0, "content2").unwrap(); + file::write_all(&file3.0, "content3").unwrap(); + file::write_all(&file4.0, "content4").unwrap(); + file::write_all(&file5.0, "content5").unwrap(); + + file::write_all(&file1.1, "old content1").unwrap(); + file::write_all(&file3.1, "old content3").unwrap(); + file::write_all(&file4.1, "old content4").unwrap(); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file3.0.exists()); + assert!(file4.0.exists()); + assert!(file5.0.exists()); + assert!(file1.1.exists()); + assert!(!file2.1.exists()); + assert!(file3.1.exists()); + assert!(file4.1.exists()); + assert!(!file5.1.exists()); + + let mut options = dir::CopyOptions::new(); + options.skip_exist = true; + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let mut from_paths = Vec::new(); + from_paths.push(dir1.0.as_path()); + from_paths.push(dir2.0.as_path()); + from_paths.push(file1.0.as_path()); + from_paths.push(file2.0.as_path()); + + let func_test = |process_info: TransitProcess| { + tx.send(process_info).unwrap(); + dir::TransitProcessResult::ContinueOrAbort + }; + + let result = copy_items_with_progress(&from_paths, &path_to, &options, func_test).unwrap(); + + assert_eq!(16, result); + assert!(!compare_dir(&dir1.0, &path_to)); + assert!(compare_dir(&dir2.0, &path_to)); + assert!(!files_eq(&file1.0, &file1.1)); + assert!(files_eq(&file2.0, &file2.1)); + }) + .join(); + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } + + match rx.recv() { + Err(_) => panic!("Errors should not be!"), + _ => {} + } +} + +#[test] +fn it_copy_with_progress_exist_overwrite_and_skip_exist() { + let test_dir = + Path::new(TEST_FOLDER).join("it_copy_with_progress_exist_overwrite_and_skip_exist"); + let path_to = test_dir.join("out"); + let dir1 = (test_dir.join("dir1"), path_to.join("dir1")); + let dir2 = (test_dir.join("dir2"), path_to.join("dir2")); + let sub = (dir1.0.join("sub"), dir1.1.join("sub")); + let file1 = (test_dir.join("file1.txt"), path_to.join("file1.txt")); + let file2 = (test_dir.join("file2.txt"), path_to.join("file2.txt")); + let file3 = (dir1.0.join("file3.txt"), dir1.1.join("file3.txt")); + let file4 = (sub.0.join("file4.txt"), sub.1.join("file4.txt")); + let file5 = (dir2.0.join("file5.txt"), dir2.1.join("file5.txt")); + + match dir::create_all(&path_to, true) { + Ok(_) => {} + Err(_) => {} + }; + + dir::create_all(&dir1.0, true).unwrap(); + dir::create_all(&dir2.0, true).unwrap(); + dir::create_all(&sub.0, true).unwrap(); + dir::create_all(&sub.1, true).unwrap(); + + assert!(dir1.0.exists()); + assert!(dir1.1.exists()); + assert!(dir2.0.exists()); + assert!(!dir2.1.exists()); + assert!(sub.0.exists()); + assert!(sub.1.exists()); + + file::write_all(&file1.0, "content1").unwrap(); + file::write_all(&file2.0, "content2").unwrap(); + file::write_all(&file3.0, "content3").unwrap(); + file::write_all(&file4.0, "content4").unwrap(); + file::write_all(&file5.0, "content5").unwrap(); + + file::write_all(&file1.1, "old content1").unwrap(); + file::write_all(&file3.1, "old content3").unwrap(); + file::write_all(&file4.1, "old content4").unwrap(); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file3.0.exists()); + assert!(file4.0.exists()); + assert!(file5.0.exists()); + assert!(file1.1.exists()); + assert!(!file2.1.exists()); + assert!(file3.1.exists()); + assert!(file4.1.exists()); + assert!(!file5.1.exists()); + + let mut options = dir::CopyOptions::new(); + options.overwrite = true; + options.skip_exist = true; + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let mut from_paths = Vec::new(); + from_paths.push(dir1.0.as_path()); + from_paths.push(dir2.0.as_path()); + from_paths.push(file1.0.as_path()); + from_paths.push(file2.0.as_path()); + + let func_test = |process_info: TransitProcess| { + tx.send(process_info).unwrap(); + dir::TransitProcessResult::ContinueOrAbort + }; + + let result = copy_items_with_progress(&from_paths, &path_to, &options, func_test).unwrap(); + + assert_eq!(40, result); + assert!(compare_dir(&dir1.0, &path_to)); + assert!(compare_dir(&dir2.0, &path_to)); + assert!(files_eq(&file1.0, &file1.1)); + assert!(files_eq(&file2.0, &file2.1)); + }) + .join(); + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } + + match rx.recv() { + Err(_) => panic!("Errors should not be!"), + _ => {} + } +} + +#[test] +fn it_copy_with_progress_using_first_levels() { + let test_dir = Path::new(TEST_FOLDER).join("it_copy_with_progress_using_first_levels"); + let path_to = test_dir.join("out"); + let d_level_1 = (test_dir.join("d_level_1"), path_to.join("d_level_1")); + let d_level_2 = (d_level_1.0.join("d_level_2"), d_level_1.1.join("d_level_2")); + let d_level_3 = (d_level_2.0.join("d_level_3"), d_level_2.1.join("d_level_3")); + let d_level_4 = (d_level_3.0.join("d_level_4"), d_level_3.1.join("d_level_4")); + let d_level_5 = (d_level_4.0.join("d_level_5"), d_level_4.1.join("d_level_5")); + + let d2_level_1 = (test_dir.join("d2_level_1"), path_to.join("d2_level_1")); + let d2_level_2 = ( + d_level_1.0.join("d2_level_2"), + d_level_1.1.join("d2_level_2"), + ); + let d2_level_3 = ( + d_level_2.0.join("d2_level_3"), + d_level_2.1.join("d2_level_3"), + ); + let d2_level_4 = ( + d_level_3.0.join("d2_level_4"), + d_level_3.1.join("d2_level_4"), + ); + let d2_level_5 = ( + d_level_4.0.join("d2_level_5"), + d_level_4.1.join("d2_level_5"), + ); + + let d3_level_1 = (test_dir.join("d3_level_1"), path_to.join("d3_level_1")); + + let file1 = (d_level_1.0.join("file1.txt"), d_level_1.1.join("file1.txt")); + let file2 = (d_level_2.0.join("file2.txt"), d_level_2.1.join("file2.txt")); + let file3 = (d_level_3.0.join("file3.txt"), d_level_3.1.join("file3.txt")); + let file4 = (d_level_4.0.join("file4.txt"), d_level_4.1.join("file4.txt")); + let file5 = (d_level_5.0.join("file5.txt"), d_level_5.1.join("file5.txt")); + + let file21 = ( + d2_level_1.0.join("file21.txt"), + d2_level_1.1.join("file21.txt"), + ); + let file22 = ( + d2_level_2.0.join("file22.txt"), + d2_level_2.1.join("file22.txt"), + ); + let file23 = ( + d2_level_3.0.join("file23.txt"), + d2_level_3.1.join("file23.txt"), + ); + let file24 = ( + d2_level_4.0.join("file24.txt"), + d2_level_4.1.join("file24.txt"), + ); + let file25 = ( + d2_level_5.0.join("file25.txt"), + d2_level_5.1.join("file25.txt"), + ); + + let file31 = ( + d3_level_1.0.join("file31.txt"), + d3_level_1.1.join("file31.txt"), + ); + + dir::create_all(&d_level_1.0, true).unwrap(); + dir::create_all(&d_level_2.0, true).unwrap(); + dir::create_all(&d_level_3.0, true).unwrap(); + dir::create_all(&d_level_4.0, true).unwrap(); + dir::create_all(&d_level_5.0, true).unwrap(); + dir::create_all(&path_to, true).unwrap(); + + dir::create_all(&d2_level_1.0, true).unwrap(); + dir::create_all(&d2_level_2.0, true).unwrap(); + dir::create_all(&d2_level_3.0, true).unwrap(); + dir::create_all(&d2_level_4.0, true).unwrap(); + dir::create_all(&d2_level_5.0, true).unwrap(); + + dir::create_all(&d3_level_1.0, true).unwrap(); + + assert!(path_to.exists()); + assert!(d_level_1.0.exists()); + assert!(d_level_2.0.exists()); + assert!(d_level_3.0.exists()); + assert!(d_level_4.0.exists()); + assert!(d_level_5.0.exists()); + + assert!(d2_level_1.0.exists()); + assert!(d2_level_2.0.exists()); + assert!(d2_level_3.0.exists()); + assert!(d2_level_4.0.exists()); + assert!(d2_level_5.0.exists()); + + assert!(d3_level_1.0.exists()); + + assert!(!d_level_1.1.exists()); + assert!(!d_level_2.1.exists()); + assert!(!d_level_3.1.exists()); + assert!(!d_level_4.1.exists()); + assert!(!d_level_5.1.exists()); + + assert!(!d2_level_1.1.exists()); + assert!(!d2_level_2.1.exists()); + assert!(!d2_level_3.1.exists()); + assert!(!d2_level_4.1.exists()); + assert!(!d2_level_5.1.exists()); + + assert!(!d3_level_1.1.exists()); + + fs_extra::file::write_all(&file1.0, "content1").unwrap(); + fs_extra::file::write_all(&file2.0, "content2").unwrap(); + fs_extra::file::write_all(&file3.0, "content3").unwrap(); + fs_extra::file::write_all(&file4.0, "content4").unwrap(); + fs_extra::file::write_all(&file5.0, "content5").unwrap(); + + fs_extra::file::write_all(&file21.0, "2content1").unwrap(); + fs_extra::file::write_all(&file22.0, "2content2").unwrap(); + fs_extra::file::write_all(&file23.0, "2content3").unwrap(); + fs_extra::file::write_all(&file24.0, "2content4").unwrap(); + fs_extra::file::write_all(&file25.0, "2content5").unwrap(); + + fs_extra::file::write_all(&file31.0, "3content1").unwrap(); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file3.0.exists()); + assert!(file4.0.exists()); + assert!(file5.0.exists()); + + assert!(file21.0.exists()); + assert!(file22.0.exists()); + assert!(file23.0.exists()); + assert!(file24.0.exists()); + assert!(file25.0.exists()); + + assert!(file31.0.exists()); + + assert!(!file1.1.exists()); + assert!(!file2.1.exists()); + assert!(!file3.1.exists()); + assert!(!file4.1.exists()); + assert!(!file5.1.exists()); + + assert!(!file21.1.exists()); + assert!(!file22.1.exists()); + assert!(!file23.1.exists()); + assert!(!file24.1.exists()); + assert!(!file25.1.exists()); + + assert!(!file31.1.exists()); + + let mut options = dir::CopyOptions::new(); + options.depth = 1; + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let mut from_paths = Vec::new(); + from_paths.push(d_level_1.0.as_path()); + from_paths.push(d2_level_1.0.as_path()); + from_paths.push(d3_level_1.0.as_path()); + + let func_test = |process_info: TransitProcess| { + tx.send(process_info).unwrap(); + dir::TransitProcessResult::ContinueOrAbort + }; + + let result = copy_items_with_progress(&from_paths, &path_to, &options, func_test).unwrap(); + + assert_eq!(26, result); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file3.0.exists()); + assert!(file4.0.exists()); + assert!(file5.0.exists()); + + assert!(file21.0.exists()); + assert!(file22.0.exists()); + assert!(file23.0.exists()); + assert!(file24.0.exists()); + assert!(file25.0.exists()); + + assert!(file31.0.exists()); + + assert!(file1.1.exists()); + assert!(!file2.1.exists()); + assert!(!file3.1.exists()); + assert!(!file4.1.exists()); + assert!(!file5.1.exists()); + + assert!(file21.1.exists()); + assert!(!file22.1.exists()); + assert!(!file23.1.exists()); + assert!(!file24.1.exists()); + assert!(!file25.1.exists()); + + assert!(file31.1.exists()); + assert!(files_eq(&file1.0, &file1.1)); + assert!(files_eq(&file21.0, &file21.1)); + assert!(files_eq(&file31.0, &file31.1)); + }) + .join(); + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } + + match rx.recv() { + Err(_) => panic!("Errors should not be!"), + _ => {} + } +} + +#[test] +fn it_copy_with_progress_using_four_levels() { + let test_dir = Path::new(TEST_FOLDER).join("it_copy_with_progress_using_four_levels"); + let path_to = test_dir.join("out"); + let d_level_1 = (test_dir.join("d_level_1"), path_to.join("d_level_1")); + let d_level_2 = (d_level_1.0.join("d_level_2"), d_level_1.1.join("d_level_2")); + let d_level_3 = (d_level_2.0.join("d_level_3"), d_level_2.1.join("d_level_3")); + let d_level_4 = (d_level_3.0.join("d_level_4"), d_level_3.1.join("d_level_4")); + let d_level_5 = (d_level_4.0.join("d_level_5"), d_level_4.1.join("d_level_5")); + + let d2_level_1 = (test_dir.join("d2_level_1"), path_to.join("d2_level_1")); + let d2_level_2 = ( + d_level_1.0.join("d2_level_2"), + d_level_1.1.join("d2_level_2"), + ); + let d2_level_3 = ( + d_level_2.0.join("d2_level_3"), + d_level_2.1.join("d2_level_3"), + ); + let d2_level_4 = ( + d_level_3.0.join("d2_level_4"), + d_level_3.1.join("d2_level_4"), + ); + let d2_level_5 = ( + d_level_4.0.join("d2_level_5"), + d_level_4.1.join("d2_level_5"), + ); + + let d3_level_1 = (test_dir.join("d3_level_1"), path_to.join("d3_level_1")); + + let file1 = (d_level_1.0.join("file1.txt"), d_level_1.1.join("file1.txt")); + let file2 = (d_level_2.0.join("file2.txt"), d_level_2.1.join("file2.txt")); + let file3 = (d_level_3.0.join("file3.txt"), d_level_3.1.join("file3.txt")); + let file4 = (d_level_4.0.join("file4.txt"), d_level_4.1.join("file4.txt")); + let file5 = (d_level_5.0.join("file5.txt"), d_level_5.1.join("file5.txt")); + + let file21 = ( + d2_level_1.0.join("file21.txt"), + d2_level_1.1.join("file21.txt"), + ); + let file22 = ( + d2_level_2.0.join("file22.txt"), + d2_level_2.1.join("file22.txt"), + ); + let file23 = ( + d2_level_3.0.join("file23.txt"), + d2_level_3.1.join("file23.txt"), + ); + let file24 = ( + d2_level_4.0.join("file24.txt"), + d2_level_4.1.join("file24.txt"), + ); + let file25 = ( + d2_level_5.0.join("file25.txt"), + d2_level_5.1.join("file25.txt"), + ); + + let file31 = ( + d3_level_1.0.join("file31.txt"), + d3_level_1.1.join("file31.txt"), + ); + + dir::create_all(&d_level_1.0, true).unwrap(); + dir::create_all(&d_level_2.0, true).unwrap(); + dir::create_all(&d_level_3.0, true).unwrap(); + dir::create_all(&d_level_4.0, true).unwrap(); + dir::create_all(&d_level_5.0, true).unwrap(); + dir::create_all(&path_to, true).unwrap(); + + dir::create_all(&d2_level_1.0, true).unwrap(); + dir::create_all(&d2_level_2.0, true).unwrap(); + dir::create_all(&d2_level_3.0, true).unwrap(); + dir::create_all(&d2_level_4.0, true).unwrap(); + dir::create_all(&d2_level_5.0, true).unwrap(); + + dir::create_all(&d3_level_1.0, true).unwrap(); + + assert!(path_to.exists()); + assert!(d_level_1.0.exists()); + assert!(d_level_2.0.exists()); + assert!(d_level_3.0.exists()); + assert!(d_level_4.0.exists()); + assert!(d_level_5.0.exists()); + + assert!(d2_level_1.0.exists()); + assert!(d2_level_2.0.exists()); + assert!(d2_level_3.0.exists()); + assert!(d2_level_4.0.exists()); + assert!(d2_level_5.0.exists()); + + assert!(d3_level_1.0.exists()); + + assert!(!d_level_1.1.exists()); + assert!(!d_level_2.1.exists()); + assert!(!d_level_3.1.exists()); + assert!(!d_level_4.1.exists()); + assert!(!d_level_5.1.exists()); + + assert!(!d2_level_1.1.exists()); + assert!(!d2_level_2.1.exists()); + assert!(!d2_level_3.1.exists()); + assert!(!d2_level_4.1.exists()); + assert!(!d2_level_5.1.exists()); + + assert!(!d3_level_1.1.exists()); + + fs_extra::file::write_all(&file1.0, "content1").unwrap(); + fs_extra::file::write_all(&file2.0, "content2").unwrap(); + fs_extra::file::write_all(&file3.0, "content3").unwrap(); + fs_extra::file::write_all(&file4.0, "content4").unwrap(); + fs_extra::file::write_all(&file5.0, "content5").unwrap(); + + fs_extra::file::write_all(&file21.0, "2content1").unwrap(); + fs_extra::file::write_all(&file22.0, "2content2").unwrap(); + fs_extra::file::write_all(&file23.0, "2content3").unwrap(); + fs_extra::file::write_all(&file24.0, "2content4").unwrap(); + fs_extra::file::write_all(&file25.0, "2content5").unwrap(); + + fs_extra::file::write_all(&file31.0, "3content1").unwrap(); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file3.0.exists()); + assert!(file4.0.exists()); + assert!(file5.0.exists()); + + assert!(file21.0.exists()); + assert!(file22.0.exists()); + assert!(file23.0.exists()); + assert!(file24.0.exists()); + assert!(file25.0.exists()); + + assert!(file31.0.exists()); + + assert!(!file1.1.exists()); + assert!(!file2.1.exists()); + assert!(!file3.1.exists()); + assert!(!file4.1.exists()); + assert!(!file5.1.exists()); + + assert!(!file21.1.exists()); + assert!(!file22.1.exists()); + assert!(!file23.1.exists()); + assert!(!file24.1.exists()); + assert!(!file25.1.exists()); + + assert!(!file31.1.exists()); + + let mut options = dir::CopyOptions::new(); + options.depth = 4; + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let mut from_paths = Vec::new(); + from_paths.push(d_level_1.0.as_path()); + from_paths.push(d2_level_1.0.as_path()); + from_paths.push(d3_level_1.0.as_path()); + + let func_test = |process_info: TransitProcess| { + tx.send(process_info).unwrap(); + dir::TransitProcessResult::ContinueOrAbort + }; + + let result = copy_items_with_progress(&from_paths, &path_to, &options, func_test).unwrap(); + + assert_eq!(77, result); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file3.0.exists()); + assert!(file4.0.exists()); + assert!(file5.0.exists()); + + assert!(file21.0.exists()); + assert!(file22.0.exists()); + assert!(file23.0.exists()); + assert!(file24.0.exists()); + assert!(file25.0.exists()); + + assert!(file31.0.exists()); + + assert!(file1.1.exists()); + assert!(file2.1.exists()); + assert!(file3.1.exists()); + assert!(file4.1.exists()); + assert!(!file5.1.exists()); + + assert!(file21.1.exists()); + assert!(file22.1.exists()); + assert!(file23.1.exists()); + assert!(file24.1.exists()); + assert!(!file25.1.exists()); + + assert!(file31.1.exists()); + assert!(files_eq(&file1.0, &file1.1)); + assert!(files_eq(&file21.0, &file21.1)); + assert!(files_eq(&file31.0, &file31.1)); + }) + .join(); + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } + + match rx.recv() { + Err(_) => panic!("Errors should not be!"), + _ => {} + } +} + +#[test] +fn it_copy_with_progress_content_only_opton() { + let test_dir = Path::new(TEST_FOLDER).join("it_copy_with_progress_content_only_opton"); + let path_to = test_dir.join("out"); + + let file1 = (test_dir.join("file1.txt"), path_to.join("file1.txt")); + + let mut options = dir::CopyOptions::new(); + options.content_only = true; + let func_test = |process_info: TransitProcess| { + println!("{}", process_info.total_bytes); + dir::TransitProcessResult::ContinueOrAbort + }; + match copy_items_with_progress(&vec![&file1.0], &file1.1, &options, func_test) { + Ok(_) => panic!("Should be a error!"), + Err(err) => match err.kind { + ErrorKind::Other => {} + _ => panic!(format!("wrong error {}", err.to_string())), + }, + }; +} + +#[test] +fn it_move_work() { + let test_dir = Path::new(TEST_FOLDER).join("it_move_work"); + let path_to = test_dir.join("out"); + let dir1 = (test_dir.join("dir1"), path_to.join("dir1")); + let dir2 = (test_dir.join("dir2"), path_to.join("dir2")); + let sub = (dir1.0.join("sub"), dir1.1.join("sub")); + let file1 = (test_dir.join("file1.txt"), path_to.join("file1.txt")); + let file2 = (test_dir.join("file2.txt"), path_to.join("file2.txt")); + let file3 = (dir1.0.join("file3.txt"), dir1.1.join("file3.txt")); + let file4 = (sub.0.join("file4.txt"), sub.1.join("file4.txt")); + let file5 = (dir2.0.join("file5.txt"), dir2.1.join("file5.txt")); + + match dir::create_all(&path_to, true) { + Ok(_) => {} + Err(_) => {} + }; + dir::create_all(&dir1.0, true).unwrap(); + dir::create_all(&dir2.0, true).unwrap(); + dir::create_all(&sub.0, true).unwrap(); + + assert!(dir1.0.exists()); + assert!(!dir1.1.exists()); + assert!(dir2.0.exists()); + assert!(!dir2.1.exists()); + assert!(sub.0.exists()); + assert!(!sub.1.exists()); + + file::write_all(&file1.0, "content1").unwrap(); + file::write_all(&file2.0, "content2").unwrap(); + file::write_all(&file3.0, "content3").unwrap(); + file::write_all(&file4.0, "content4").unwrap(); + file::write_all(&file5.0, "content5").unwrap(); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file3.0.exists()); + assert!(file4.0.exists()); + assert!(file5.0.exists()); + assert!(!file1.1.exists()); + assert!(!file2.1.exists()); + assert!(!file3.1.exists()); + assert!(!file4.1.exists()); + assert!(!file5.1.exists()); + + let mut from_paths = Vec::new(); + from_paths.push(dir1.0.as_path()); + from_paths.push(dir2.0.as_path()); + from_paths.push(file1.0.as_path()); + from_paths.push(file2.0.as_path()); + + let options = dir::CopyOptions::new(); + let result = move_items(&from_paths, &path_to, &options).unwrap(); + + assert_eq!(40, result); + assert!(!file1.0.exists()); + assert!(!file2.0.exists()); + assert!(!file3.0.exists()); + assert!(!file4.0.exists()); + assert!(!file5.0.exists()); + assert!(file1.1.exists()); + assert!(file2.1.exists()); + assert!(file3.1.exists()); + assert!(file4.1.exists()); + assert!(file5.1.exists()); +} + +#[test] +fn it_move_source_not_exist() { + let test_dir = Path::new(TEST_FOLDER).join("it_move_source_not_exist"); + let path_to = test_dir.join("out"); + let dir1 = (test_dir.join("dir1"), path_to.join("dir1")); + let dir2 = (test_dir.join("dir2"), path_to.join("dir2")); + let sub = (dir1.0.join("sub"), dir1.1.join("sub")); + let file1 = (test_dir.join("file1.txt"), path_to.join("file1.txt")); + + match dir::create_all(&path_to, true) { + Ok(_) => {} + Err(_) => {} + }; + + assert!(!dir1.0.exists()); + assert!(!dir1.1.exists()); + assert!(!dir2.0.exists()); + assert!(!dir2.1.exists()); + assert!(!sub.0.exists()); + assert!(!sub.1.exists()); + + assert!(!file1.0.exists()); + assert!(!file1.1.exists()); + + let mut from_paths = Vec::new(); + from_paths.push(dir1.0.as_path()); + from_paths.push(dir2.0.as_path()); + from_paths.push(file1.0.as_path()); + + let options = dir::CopyOptions::new(); + match move_items(&from_paths, &path_to, &options) { + Ok(_) => panic!("Should be a error!"), + Err(err) => match err.kind { + ErrorKind::NotFound => {} + _ => {} + }, + }; +} + +#[test] +fn it_move_exist_overwrite() { + let test_dir = Path::new(TEST_FOLDER).join("it_move_exist_overwrite"); + let path_to = test_dir.join("out"); + let dir1 = (test_dir.join("dir1"), path_to.join("dir1")); + let dir2 = (test_dir.join("dir2"), path_to.join("dir2")); + let sub = (dir1.0.join("sub"), dir1.1.join("sub")); + let file1 = (test_dir.join("file1.txt"), path_to.join("file1.txt")); + let file2 = (test_dir.join("file2.txt"), path_to.join("file2.txt")); + let file3 = (dir1.0.join("file3.txt"), dir1.1.join("file3.txt")); + let file4 = (sub.0.join("file4.txt"), sub.1.join("file4.txt")); + let file5 = (dir2.0.join("file5.txt"), dir2.1.join("file5.txt")); + + match dir::create_all(&path_to, true) { + Ok(_) => {} + Err(_) => {} + }; + + dir::create_all(&dir1.0, true).unwrap(); + dir::create_all(&dir2.0, true).unwrap(); + dir::create_all(&sub.0, true).unwrap(); + dir::create_all(&sub.1, true).unwrap(); + + assert!(dir1.0.exists()); + assert!(dir1.1.exists()); + assert!(dir2.0.exists()); + assert!(!dir2.1.exists()); + assert!(sub.0.exists()); + assert!(sub.1.exists()); + + file::write_all(&file1.0, "content1").unwrap(); + file::write_all(&file2.0, "content2").unwrap(); + file::write_all(&file3.0, "content3").unwrap(); + file::write_all(&file4.0, "content4").unwrap(); + file::write_all(&file5.0, "content5").unwrap(); + + file::write_all(&file1.1, "old content1").unwrap(); + file::write_all(&file3.1, "old content3").unwrap(); + file::write_all(&file4.1, "old content4").unwrap(); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file3.0.exists()); + assert!(file4.0.exists()); + assert!(file5.0.exists()); + assert!(file1.1.exists()); + assert!(!file2.1.exists()); + assert!(file3.1.exists()); + assert!(file4.1.exists()); + assert!(!file5.1.exists()); + + let mut from_paths = Vec::new(); + from_paths.push(dir1.0.as_path()); + from_paths.push(dir2.0.as_path()); + from_paths.push(file1.0.as_path()); + from_paths.push(file2.0.as_path()); + + let mut options = dir::CopyOptions::new(); + options.overwrite = true; + let result = move_items(&from_paths, &path_to, &options).unwrap(); + + assert_eq!(40, result); + assert!(!file1.0.exists()); + assert!(!file2.0.exists()); + assert!(!file3.0.exists()); + assert!(!file4.0.exists()); + assert!(!file5.0.exists()); + assert!(file1.1.exists()); + assert!(file2.1.exists()); + assert!(file3.1.exists()); + assert!(file4.1.exists()); + assert!(file5.1.exists()); +} + +#[test] +fn it_move_exist_not_overwrite() { + let test_dir = Path::new(TEST_FOLDER).join("it_move_exist_not_overwrite"); + let path_to = test_dir.join("out"); + let dir1 = (test_dir.join("dir1"), path_to.join("dir1")); + let dir2 = (test_dir.join("dir2"), path_to.join("dir2")); + let sub = (dir1.0.join("sub"), dir1.1.join("sub")); + let file1 = (test_dir.join("file1.txt"), path_to.join("file1.txt")); + let file2 = (test_dir.join("file2.txt"), path_to.join("file2.txt")); + let file3 = (dir1.0.join("file3.txt"), dir1.1.join("file3.txt")); + let file4 = (sub.0.join("file4.txt"), sub.1.join("file4.txt")); + let file5 = (dir2.0.join("file5.txt"), dir2.1.join("file5.txt")); + + match dir::create_all(&path_to, true) { + Ok(_) => {} + Err(_) => {} + }; + + dir::create_all(&dir1.0, true).unwrap(); + dir::create_all(&dir2.0, true).unwrap(); + dir::create_all(&sub.0, true).unwrap(); + dir::create_all(&sub.1, true).unwrap(); + + assert!(dir1.0.exists()); + assert!(dir1.1.exists()); + assert!(dir2.0.exists()); + assert!(!dir2.1.exists()); + assert!(sub.0.exists()); + assert!(sub.1.exists()); + + file::write_all(&file1.0, "content1").unwrap(); + file::write_all(&file2.0, "content2").unwrap(); + file::write_all(&file3.0, "content3").unwrap(); + file::write_all(&file4.0, "content4").unwrap(); + file::write_all(&file5.0, "content5").unwrap(); + + file::write_all(&file1.1, "old content1").unwrap(); + file::write_all(&file3.1, "old content3").unwrap(); + file::write_all(&file4.1, "old content4").unwrap(); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file3.0.exists()); + assert!(file4.0.exists()); + assert!(file5.0.exists()); + assert!(file1.1.exists()); + assert!(!file2.1.exists()); + assert!(file3.1.exists()); + assert!(file4.1.exists()); + assert!(!file5.1.exists()); + + let mut from_paths = Vec::new(); + from_paths.push(dir1.0.as_path()); + from_paths.push(dir2.0.as_path()); + from_paths.push(file1.0.as_path()); + from_paths.push(file2.0.as_path()); + + let options = dir::CopyOptions::new(); + match move_items(&from_paths, &path_to, &options) { + Ok(_) => panic!("Should be a error!"), + Err(err) => match err.kind { + ErrorKind::AlreadyExists => {} + _ => panic!(format!("{}", err.to_string())), + }, + }; +} + +#[test] +fn it_move_exist_skip() { + let test_dir = Path::new(TEST_FOLDER).join("it_move_exist_skip"); + let path_to = test_dir.join("out"); + let dir1 = (test_dir.join("dir1"), path_to.join("dir1")); + let dir2 = (test_dir.join("dir2"), path_to.join("dir2")); + let sub = (dir1.0.join("sub"), dir1.1.join("sub")); + let file1 = (test_dir.join("file1.txt"), path_to.join("file1.txt")); + let file2 = (test_dir.join("file2.txt"), path_to.join("file2.txt")); + let file3 = (dir1.0.join("file3.txt"), dir1.1.join("file3.txt")); + let file4 = (sub.0.join("file4.txt"), sub.1.join("file4.txt")); + let file5 = (dir2.0.join("file5.txt"), dir2.1.join("file5.txt")); + + match dir::create_all(&path_to, true) { + Ok(_) => {} + Err(_) => {} + }; + + dir::create_all(&dir1.0, true).unwrap(); + dir::create_all(&dir2.0, true).unwrap(); + dir::create_all(&sub.0, true).unwrap(); + dir::create_all(&sub.1, true).unwrap(); + + assert!(dir1.0.exists()); + assert!(dir1.1.exists()); + assert!(dir2.0.exists()); + assert!(!dir2.1.exists()); + assert!(sub.0.exists()); + assert!(sub.1.exists()); + + file::write_all(&file1.0, "content1").unwrap(); + file::write_all(&file2.0, "content2").unwrap(); + file::write_all(&file3.0, "content3").unwrap(); + file::write_all(&file4.0, "content4").unwrap(); + file::write_all(&file5.0, "content5").unwrap(); + + file::write_all(&file1.1, "old content1").unwrap(); + file::write_all(&file3.1, "old content3").unwrap(); + file::write_all(&file4.1, "old content4").unwrap(); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file3.0.exists()); + assert!(file4.0.exists()); + assert!(file5.0.exists()); + assert!(file1.1.exists()); + assert!(!file2.1.exists()); + assert!(file3.1.exists()); + assert!(file4.1.exists()); + assert!(!file5.1.exists()); + + let mut from_paths = Vec::new(); + from_paths.push(dir1.0.as_path()); + from_paths.push(dir2.0.as_path()); + from_paths.push(file1.0.as_path()); + from_paths.push(file2.0.as_path()); + + let mut options = dir::CopyOptions::new(); + options.skip_exist = true; + let result = move_items(&from_paths, &path_to, &options).unwrap(); + + assert_eq!(16, result); + assert!(!files_eq(&file1.0, &file1.1)); + assert!(!file2.0.exists()); + assert!(!files_eq(&file3.0, &file3.1)); + assert!(!files_eq(&file4.0, &file4.1)); + assert!(!file5.0.exists()); +} + +#[test] +fn it_move_exist_overwrite_and_skip_exist() { + let test_dir = Path::new(TEST_FOLDER).join("it_move_exist_overwrite_and_skip_exist"); + let path_to = test_dir.join("out"); + let dir1 = (test_dir.join("dir1"), path_to.join("dir1")); + let dir2 = (test_dir.join("dir2"), path_to.join("dir2")); + let sub = (dir1.0.join("sub"), dir1.1.join("sub")); + let file1 = (test_dir.join("file1.txt"), path_to.join("file1.txt")); + let file2 = (test_dir.join("file2.txt"), path_to.join("file2.txt")); + let file3 = (dir1.0.join("file3.txt"), dir1.1.join("file3.txt")); + let file4 = (sub.0.join("file4.txt"), sub.1.join("file4.txt")); + let file5 = (dir2.0.join("file5.txt"), dir2.1.join("file5.txt")); + + match dir::create_all(&path_to, true) { + Ok(_) => {} + Err(_) => {} + }; + + dir::create_all(&dir1.0, true).unwrap(); + dir::create_all(&dir2.0, true).unwrap(); + dir::create_all(&sub.0, true).unwrap(); + dir::create_all(&sub.1, true).unwrap(); + + assert!(dir1.0.exists()); + assert!(dir1.1.exists()); + assert!(dir2.0.exists()); + assert!(!dir2.1.exists()); + assert!(sub.0.exists()); + assert!(sub.1.exists()); + + file::write_all(&file1.0, "content1").unwrap(); + file::write_all(&file2.0, "content2").unwrap(); + file::write_all(&file3.0, "content3").unwrap(); + file::write_all(&file4.0, "content4").unwrap(); + file::write_all(&file5.0, "content5").unwrap(); + + file::write_all(&file1.1, "old content1").unwrap(); + file::write_all(&file3.1, "old content3").unwrap(); + file::write_all(&file4.1, "old content4").unwrap(); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file3.0.exists()); + assert!(file4.0.exists()); + assert!(file5.0.exists()); + assert!(file1.1.exists()); + assert!(!file2.1.exists()); + assert!(file3.1.exists()); + assert!(file4.1.exists()); + assert!(!file5.1.exists()); + + let mut from_paths = Vec::new(); + from_paths.push(dir1.0.as_path()); + from_paths.push(dir2.0.as_path()); + from_paths.push(file1.0.as_path()); + from_paths.push(file2.0.as_path()); + + let mut options = dir::CopyOptions::new(); + options.overwrite = true; + options.skip_exist = true; + let result = move_items(&from_paths, &path_to, &options).unwrap(); + + assert_eq!(40, result); + assert!(!file1.0.exists()); + assert!(!file2.0.exists()); + assert!(!file3.0.exists()); + assert!(!file4.0.exists()); + assert!(!file5.0.exists()); + assert!(file1.1.exists()); + assert!(file2.1.exists()); + assert!(file3.1.exists()); + assert!(file4.1.exists()); + assert!(file5.1.exists()); +} +#[test] +fn it_move_content_only_option() { + let test_dir = Path::new(TEST_FOLDER).join("it_move_content_only_option"); + let path_to = test_dir.join("out"); + + let file1 = (test_dir.join("file1.txt"), path_to.join("file1.txt")); + + let mut options = dir::CopyOptions::new(); + options.content_only = true; + match move_items(&vec![&file1.0], &file1.1, &options) { + Err(err) => match err.kind { + ErrorKind::Other => { + assert_eq!(1, 1); + } + _ => { + panic!(format!("wrong error {}", err.to_string())); + } + }, + Ok(_) => { + panic!("should be error"); + } + } +} + +#[test] +fn it_move_progress_work() { + let test_dir = Path::new(TEST_FOLDER).join("it_move_progress_work"); + let path_to = test_dir.join("out"); + let dir1 = (test_dir.join("dir1"), path_to.join("dir1")); + let dir2 = (test_dir.join("dir2"), path_to.join("dir2")); + let sub = (dir1.0.join("sub"), dir1.1.join("sub")); + let file1 = (test_dir.join("file1.txt"), path_to.join("file1.txt")); + let file2 = (test_dir.join("file2.txt"), path_to.join("file2.txt")); + let file3 = (dir1.0.join("file3.txt"), dir1.1.join("file3.txt")); + let file4 = (sub.0.join("file4.txt"), sub.1.join("file4.txt")); + let file5 = (dir2.0.join("file5.txt"), dir2.1.join("file5.txt")); + + match dir::create_all(&path_to, true) { + Ok(_) => {} + Err(_) => {} + }; + dir::create_all(&dir1.0, true).unwrap(); + dir::create_all(&dir2.0, true).unwrap(); + dir::create_all(&sub.0, true).unwrap(); + + assert!(dir1.0.exists()); + assert!(!dir1.1.exists()); + assert!(dir2.0.exists()); + assert!(!dir2.1.exists()); + assert!(sub.0.exists()); + assert!(!sub.1.exists()); + + file::write_all(&file1.0, "content1").unwrap(); + file::write_all(&file2.0, "content22").unwrap(); + file::write_all(&file3.0, "content3").unwrap(); + file::write_all(&file4.0, "content4").unwrap(); + file::write_all(&file5.0, "content5").unwrap(); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file3.0.exists()); + assert!(file4.0.exists()); + assert!(file5.0.exists()); + assert!(!file1.1.exists()); + assert!(!file2.1.exists()); + assert!(!file3.1.exists()); + assert!(!file4.1.exists()); + assert!(!file5.1.exists()); + + let options = dir::CopyOptions::new(); + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let mut from_paths = Vec::new(); + from_paths.push(dir1.0.as_path()); + from_paths.push(dir2.0.as_path()); + from_paths.push(file1.0.as_path()); + from_paths.push(file2.0.as_path()); + + let func_test = |process_info: TransitProcess| { + tx.send(process_info).unwrap(); + dir::TransitProcessResult::ContinueOrAbort + }; + let result = move_items_with_progress(&from_paths, &path_to, &options, func_test).unwrap(); + + assert_eq!(41, result); + assert!(!file1.0.exists()); + assert!(!file2.0.exists()); + assert!(!file3.0.exists()); + assert!(!file4.0.exists()); + assert!(!file5.0.exists()); + assert!(file1.1.exists()); + assert!(file2.1.exists()); + assert!(file3.1.exists()); + assert!(file4.1.exists()); + assert!(file5.1.exists()); + }) + .join(); + + loop { + match rx.try_recv() { + Ok(process_info) => { + if process_info.file_name == "file2.txt" { + assert_eq!(9, process_info.file_total_bytes); + assert_eq!(41, process_info.total_bytes); + } else if process_info.file_name == "file1.txt" { + assert_eq!(8, process_info.file_total_bytes); + assert_eq!(41, process_info.total_bytes); + } + } + Err(TryRecvError::Disconnected) => { + break; + } + Err(TryRecvError::Empty) => {} + } + } + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } +} + +#[test] +fn it_move_with_progress_source_not_exist() { + let test_dir = Path::new(TEST_FOLDER).join("it_move_with_progress_source_not_exist"); + let path_to = test_dir.join("out"); + let dir1 = (test_dir.join("dir1"), path_to.join("dir1")); + let dir2 = (test_dir.join("dir2"), path_to.join("dir2")); + let sub = (dir1.0.join("sub"), dir1.1.join("sub")); + let file1 = (test_dir.join("file1.txt"), path_to.join("file1.txt")); + + match dir::create_all(&path_to, true) { + Ok(_) => {} + Err(_) => {} + }; + + assert!(!dir1.0.exists()); + assert!(!dir1.1.exists()); + assert!(!dir2.0.exists()); + assert!(!dir2.1.exists()); + assert!(!sub.0.exists()); + assert!(!sub.1.exists()); + + assert!(!file1.0.exists()); + assert!(!file1.1.exists()); + + let mut from_paths = Vec::new(); + from_paths.push(dir1.0.as_path()); + from_paths.push(dir2.0.as_path()); + from_paths.push(file1.0.as_path()); + + let func_test = |process_info: TransitProcess| { + println!("{}", process_info.total_bytes); + dir::TransitProcessResult::ContinueOrAbort + }; + let options = dir::CopyOptions::new(); + match move_items_with_progress(&from_paths, &path_to, &options, func_test) { + Ok(_) => panic!("Should be a error!"), + Err(err) => match err.kind { + ErrorKind::NotFound => {} + _ => {} + }, + }; +} + +#[test] +fn it_move_with_progress_exist_overwrite() { + let test_dir = Path::new(TEST_FOLDER).join("it_move_with_progress_exist_overwrite"); + let path_to = test_dir.join("out"); + let dir1 = (test_dir.join("dir1"), path_to.join("dir1")); + let dir2 = (test_dir.join("dir2"), path_to.join("dir2")); + let sub = (dir1.0.join("sub"), dir1.1.join("sub")); + let file1 = (test_dir.join("file1.txt"), path_to.join("file1.txt")); + let file2 = (test_dir.join("file2.txt"), path_to.join("file2.txt")); + let file3 = (dir1.0.join("file3.txt"), dir1.1.join("file3.txt")); + let file4 = (sub.0.join("file4.txt"), sub.1.join("file4.txt")); + let file5 = (dir2.0.join("file5.txt"), dir2.1.join("file5.txt")); + + match dir::create_all(&path_to, true) { + Ok(_) => {} + Err(_) => {} + }; + + dir::create_all(&dir1.0, true).unwrap(); + dir::create_all(&dir2.0, true).unwrap(); + dir::create_all(&sub.0, true).unwrap(); + dir::create_all(&sub.1, true).unwrap(); + + assert!(dir1.0.exists()); + assert!(dir1.1.exists()); + assert!(dir2.0.exists()); + assert!(!dir2.1.exists()); + assert!(sub.0.exists()); + assert!(sub.1.exists()); + + file::write_all(&file1.0, "content1").unwrap(); + file::write_all(&file2.0, "content2").unwrap(); + file::write_all(&file3.0, "content3").unwrap(); + file::write_all(&file4.0, "content4").unwrap(); + file::write_all(&file5.0, "content5").unwrap(); + + file::write_all(&file1.1, "old content1").unwrap(); + file::write_all(&file3.1, "old content3").unwrap(); + file::write_all(&file4.1, "old content4").unwrap(); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file3.0.exists()); + assert!(file4.0.exists()); + assert!(file5.0.exists()); + assert!(file1.1.exists()); + assert!(!file2.1.exists()); + assert!(file3.1.exists()); + assert!(file4.1.exists()); + assert!(!file5.1.exists()); + + let mut options = dir::CopyOptions::new(); + options.overwrite = true; + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let mut from_paths = Vec::new(); + from_paths.push(dir1.0.as_path()); + from_paths.push(dir2.0.as_path()); + from_paths.push(file1.0.as_path()); + from_paths.push(file2.0.as_path()); + + let func_test = |process_info: TransitProcess| { + tx.send(process_info).unwrap(); + dir::TransitProcessResult::ContinueOrAbort + }; + let result = move_items_with_progress(&from_paths, &path_to, &options, func_test).unwrap(); + + assert_eq!(40, result); + assert!(!file1.0.exists()); + assert!(!file2.0.exists()); + assert!(!file3.0.exists()); + assert!(!file4.0.exists()); + assert!(!file5.0.exists()); + assert!(file1.1.exists()); + assert!(file2.1.exists()); + assert!(file3.1.exists()); + assert!(file4.1.exists()); + assert!(file5.1.exists()); + }) + .join(); + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } + + match rx.recv() { + Err(_) => panic!("Errors should not be!"), + _ => {} + } +} + +#[test] +fn it_move_with_progress_exist_not_overwrite() { + let test_dir = Path::new(TEST_FOLDER).join("it_move_with_progress_exist_not_overwrite"); + let path_to = test_dir.join("out"); + let dir1 = (test_dir.join("dir1"), path_to.join("dir1")); + let dir2 = (test_dir.join("dir2"), path_to.join("dir2")); + let sub = (dir1.0.join("sub"), dir1.1.join("sub")); + let file1 = (test_dir.join("file1.txt"), path_to.join("file1.txt")); + let file2 = (test_dir.join("file2.txt"), path_to.join("file2.txt")); + let file3 = (dir1.0.join("file3.txt"), dir1.1.join("file3.txt")); + let file4 = (sub.0.join("file4.txt"), sub.1.join("file4.txt")); + let file5 = (dir2.0.join("file5.txt"), dir2.1.join("file5.txt")); + + match dir::create_all(&path_to, true) { + Ok(_) => {} + Err(_) => {} + }; + + dir::create_all(&dir1.0, true).unwrap(); + dir::create_all(&dir2.0, true).unwrap(); + dir::create_all(&sub.0, true).unwrap(); + dir::create_all(&sub.1, true).unwrap(); + + assert!(dir1.0.exists()); + assert!(dir1.1.exists()); + assert!(dir2.0.exists()); + assert!(!dir2.1.exists()); + assert!(sub.0.exists()); + assert!(sub.1.exists()); + + file::write_all(&file1.0, "content1").unwrap(); + file::write_all(&file2.0, "content2").unwrap(); + file::write_all(&file3.0, "content3").unwrap(); + file::write_all(&file4.0, "content4").unwrap(); + file::write_all(&file5.0, "content5").unwrap(); + + file::write_all(&file1.1, "old content1").unwrap(); + file::write_all(&file3.1, "old content3").unwrap(); + file::write_all(&file4.1, "old content4").unwrap(); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file3.0.exists()); + assert!(file4.0.exists()); + assert!(file5.0.exists()); + assert!(file1.1.exists()); + assert!(!file2.1.exists()); + assert!(file3.1.exists()); + assert!(file4.1.exists()); + assert!(!file5.1.exists()); + + let mut from_paths = Vec::new(); + from_paths.push(dir1.0.as_path()); + from_paths.push(dir2.0.as_path()); + from_paths.push(file1.0.as_path()); + from_paths.push(file2.0.as_path()); + + let options = dir::CopyOptions::new(); + let func_test = |process_info: TransitProcess| { + println!("{}", process_info.total_bytes); + dir::TransitProcessResult::ContinueOrAbort + }; + match move_items_with_progress(&from_paths, &path_to, &options, func_test) { + Ok(_) => panic!("Should be a error!"), + Err(err) => match err.kind { + ErrorKind::AlreadyExists => {} + _ => panic!(format!("{}", err.to_string())), + }, + }; +} + +#[test] +fn it_move_with_progress_exist_skip_exist() { + let test_dir = Path::new(TEST_FOLDER).join("it_move_with_progress_exist_skip_exist"); + let path_to = test_dir.join("out"); + let dir1 = (test_dir.join("dir1"), path_to.join("dir1")); + let dir2 = (test_dir.join("dir2"), path_to.join("dir2")); + let sub = (dir1.0.join("sub"), dir1.1.join("sub")); + let file1 = (test_dir.join("file1.txt"), path_to.join("file1.txt")); + let file2 = (test_dir.join("file2.txt"), path_to.join("file2.txt")); + let file3 = (dir1.0.join("file3.txt"), dir1.1.join("file3.txt")); + let file4 = (sub.0.join("file4.txt"), sub.1.join("file4.txt")); + let file5 = (dir2.0.join("file5.txt"), dir2.1.join("file5.txt")); + + match dir::create_all(&path_to, true) { + Ok(_) => {} + Err(_) => {} + }; + + dir::create_all(&dir1.0, true).unwrap(); + dir::create_all(&dir2.0, true).unwrap(); + dir::create_all(&sub.0, true).unwrap(); + dir::create_all(&sub.1, true).unwrap(); + dir::create_all(&dir2.1, true).unwrap(); + + assert!(dir1.0.exists()); + assert!(dir1.1.exists()); + assert!(dir2.0.exists()); + assert!(dir2.1.exists()); + assert!(sub.0.exists()); + assert!(sub.1.exists()); + + file::write_all(&file1.0, "content1").unwrap(); + file::write_all(&file2.0, "content2").unwrap(); + file::write_all(&file3.0, "content3").unwrap(); + file::write_all(&file4.0, "content4").unwrap(); + file::write_all(&file5.0, "content5").unwrap(); + + file::write_all(&file1.1, "old content1").unwrap(); + file::write_all(&file3.1, "old content3").unwrap(); + file::write_all(&file4.1, "old content4").unwrap(); + file::write_all(&file5.1, "old content5").unwrap(); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file3.0.exists()); + assert!(file4.0.exists()); + assert!(file5.0.exists()); + assert!(file1.1.exists()); + assert!(!file2.1.exists()); + assert!(file3.1.exists()); + assert!(file4.1.exists()); + assert!(file5.1.exists()); + + let mut options = dir::CopyOptions::new(); + options.skip_exist = true; + options.overwrite = false; + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let mut from_paths = Vec::new(); + from_paths.push(dir1.0.as_path()); + from_paths.push(dir2.0.as_path()); + from_paths.push(file1.0.as_path()); + from_paths.push(file2.0.as_path()); + + let func_test = |process_info: TransitProcess| { + tx.send(process_info).unwrap(); + dir::TransitProcessResult::ContinueOrAbort + }; + let result = move_items_with_progress(&from_paths, &path_to, &options, func_test).unwrap(); + + assert_eq!(8, result); + assert!(file1.0.exists()); + assert!(!file2.0.exists()); + assert!(file3.0.exists()); + assert!(file4.0.exists()); + assert!(file5.0.exists()); + assert!(file1.1.exists()); + assert!(file2.1.exists()); + assert!(file3.1.exists()); + assert!(file4.1.exists()); + assert!(file5.1.exists()); + assert!(!files_eq(&file1.0, &file1.1)); + }) + .join(); + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } + + match rx.recv() { + Err(_) => panic!("Errors should not be!"), + _ => {} + } +} + +#[test] +fn it_move_with_progress_exist_overwrite_and_skip_exist() { + let test_dir = + Path::new(TEST_FOLDER).join("it_move_with_progress_exist_overwrite_and_skip_exist"); + let path_to = test_dir.join("out"); + let dir1 = (test_dir.join("dir1"), path_to.join("dir1")); + let dir2 = (test_dir.join("dir2"), path_to.join("dir2")); + let sub = (dir1.0.join("sub"), dir1.1.join("sub")); + let file1 = (test_dir.join("file1.txt"), path_to.join("file1.txt")); + let file2 = (test_dir.join("file2.txt"), path_to.join("file2.txt")); + let file3 = (dir1.0.join("file3.txt"), dir1.1.join("file3.txt")); + let file4 = (sub.0.join("file4.txt"), sub.1.join("file4.txt")); + let file5 = (dir2.0.join("file5.txt"), dir2.1.join("file5.txt")); + + match dir::create_all(&path_to, true) { + Ok(_) => {} + Err(_) => {} + }; + + dir::create_all(&dir1.0, true).unwrap(); + dir::create_all(&dir2.0, true).unwrap(); + dir::create_all(&sub.0, true).unwrap(); + dir::create_all(&sub.1, true).unwrap(); + + assert!(dir1.0.exists()); + assert!(dir1.1.exists()); + assert!(dir2.0.exists()); + assert!(!dir2.1.exists()); + assert!(sub.0.exists()); + assert!(sub.1.exists()); + + file::write_all(&file1.0, "content1").unwrap(); + file::write_all(&file2.0, "content2").unwrap(); + file::write_all(&file3.0, "content3").unwrap(); + file::write_all(&file4.0, "content4").unwrap(); + file::write_all(&file5.0, "content5").unwrap(); + + file::write_all(&file1.1, "old content1").unwrap(); + file::write_all(&file3.1, "old content3").unwrap(); + file::write_all(&file4.1, "old content4").unwrap(); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file3.0.exists()); + assert!(file4.0.exists()); + assert!(file5.0.exists()); + assert!(file1.1.exists()); + assert!(!file2.1.exists()); + assert!(file3.1.exists()); + assert!(file4.1.exists()); + assert!(!file5.1.exists()); + + let mut options = dir::CopyOptions::new(); + options.overwrite = true; + options.skip_exist = true; + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let mut from_paths = Vec::new(); + from_paths.push(dir1.0.as_path()); + from_paths.push(dir2.0.as_path()); + from_paths.push(file1.0.as_path()); + from_paths.push(file2.0.as_path()); + + let func_test = |process_info: TransitProcess| { + tx.send(process_info).unwrap(); + dir::TransitProcessResult::ContinueOrAbort + }; + let result = move_items_with_progress(&from_paths, &path_to, &options, func_test).unwrap(); + + assert_eq!(40, result); + assert!(!file1.0.exists()); + assert!(!file2.0.exists()); + assert!(!file3.0.exists()); + assert!(!file4.0.exists()); + assert!(!file5.0.exists()); + assert!(file1.1.exists()); + assert!(file2.1.exists()); + assert!(file3.1.exists()); + assert!(file4.1.exists()); + assert!(file5.1.exists()); + }) + .join(); + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } + + match rx.recv() { + Err(_) => panic!("Errors should not be!"), + _ => {} + } +} + +#[test] +fn it_move_with_progress_content_only_option() { + let test_dir = Path::new(TEST_FOLDER).join("it_move_with_progress_content_only_option"); + let path_to = test_dir.join("out"); + + let file1 = (test_dir.join("file1.txt"), path_to.join("file1.txt")); + + let mut options = dir::CopyOptions::new(); + options.content_only = true; + let func_test = |process_info: TransitProcess| { + println!("{}", process_info.total_bytes); + dir::TransitProcessResult::ContinueOrAbort + }; + match move_items_with_progress(&vec![&file1.0], &file1.1, &options, func_test) { + Ok(_) => panic!("Should be a error!"), + Err(err) => match err.kind { + ErrorKind::Other => {} + _ => panic!(format!("wrong error {}", err.to_string())), + }, + }; +} + +#[test] +fn it_remove_work() { + let test_dir = Path::new(TEST_FOLDER).join("it_remove_work"); + let dir1 = test_dir.join("dir1"); + let dir2 = test_dir.join("dir2"); + let sub = dir1.join("sub"); + let file1 = test_dir.join("file1.txt"); + let file2 = test_dir.join("file2.txt"); + let file3 = dir1.join("file3.txt"); + let file4 = sub.join("file4.txt"); + let file5 = dir2.join("file5.txt"); + + dir::create_all(&dir1, true).unwrap(); + dir::create_all(&dir2, true).unwrap(); + dir::create_all(&sub, true).unwrap(); + + assert!(dir1.exists()); + assert!(dir2.exists()); + assert!(sub.exists()); + + file::write_all(&file1, "content1").unwrap(); + file::write_all(&file2, "content2").unwrap(); + file::write_all(&file3, "content3").unwrap(); + file::write_all(&file4, "content4").unwrap(); + file::write_all(&file5, "content5").unwrap(); + + assert!(file1.exists()); + assert!(file2.exists()); + assert!(file3.exists()); + assert!(file4.exists()); + assert!(file5.exists()); + + let mut from_paths = Vec::new(); + from_paths.push(dir1.as_path()); + from_paths.push(dir2.as_path()); + from_paths.push(file1.as_path()); + from_paths.push(file2.as_path()); + + remove_items(&from_paths).unwrap(); + assert!(!file1.exists()); + assert!(!file2.exists()); + assert!(!file3.exists()); + assert!(!file4.exists()); + assert!(!file5.exists()); +} + +#[test] +fn it_copy_with_progress_exist_user_decide_overwrite() { + let test_dir = Path::new(TEST_FOLDER).join("it_copy_with_progress_exist_user_decide_overwrite"); + let path_to = test_dir.join("out"); + let dir1 = (test_dir.join("dir1"), path_to.join("dir1")); + let dir2 = (test_dir.join("dir2"), path_to.join("dir2")); + let sub = (dir1.0.join("sub"), dir1.1.join("sub")); + let file1 = (test_dir.join("file1.txt"), path_to.join("file1.txt")); + let file2 = (test_dir.join("file2.txt"), path_to.join("file2.txt")); + let file3 = (dir1.0.join("file3.txt"), dir1.1.join("file3.txt")); + let file4 = (sub.0.join("file4.txt"), sub.1.join("file4.txt")); + let file5 = (dir2.0.join("file5.txt"), dir2.1.join("file5.txt")); + + dir::create_all(&dir1.0, true).unwrap(); + dir::create_all(&dir1.1, true).unwrap(); + dir::create_all(&dir2.0, true).unwrap(); + dir::create_all(&dir2.1, true).unwrap(); + dir::create_all(&sub.0, true).unwrap(); + dir::create_all(&sub.1, true).unwrap(); + + assert!(&dir1.0.exists()); + assert!(&dir1.1.exists()); + assert!(&dir2.0.exists()); + assert!(&dir2.1.exists()); + assert!(&sub.0.exists()); + assert!(&sub.1.exists()); + + fs_extra::file::write_all(&file1.0, "content1").unwrap(); + fs_extra::file::write_all(&file2.0, "content2").unwrap(); + fs_extra::file::write_all(&file3.0, "content3").unwrap(); + fs_extra::file::write_all(&file4.0, "content4").unwrap(); + fs_extra::file::write_all(&file5.0, "content5").unwrap(); + + fs_extra::file::write_all(&file1.1, "old content11").unwrap(); + fs_extra::file::write_all(&file2.1, "old content12").unwrap(); + fs_extra::file::write_all(&file3.1, "old content13").unwrap(); + fs_extra::file::write_all(&file4.1, "old content14").unwrap(); + fs_extra::file::write_all(&file5.1, "old content15").unwrap(); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file3.0.exists()); + assert!(file4.0.exists()); + assert!(file5.0.exists()); + assert!(file1.1.exists()); + assert!(file2.1.exists()); + assert!(file3.1.exists()); + assert!(file4.1.exists()); + assert!(file5.1.exists()); + + let mut options = dir::CopyOptions::new(); + assert!(!compare_dir(&dir1.0, &dir1.1)); + assert!(!compare_dir(&dir2.0, &dir2.1)); + assert!(!files_eq(&file1.0, &file1.1)); + assert!(!files_eq(&file2.0, &file2.1)); + options.buffer_size = 1; + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let mut count_exist_files = 0; + let mut from_paths = Vec::new(); + from_paths.push(dir1.0.as_path()); + from_paths.push(dir2.0.as_path()); + from_paths.push(file1.0.as_path()); + from_paths.push(file2.0.as_path()); + + let result: u64; + { + let func_test = |process_info: TransitProcess| { + let result: dir::TransitProcessResult; + match process_info.state { + dir::TransitState::Exists => { + count_exist_files += 1; + result = dir::TransitProcessResult::Overwrite; + tx.send(process_info).unwrap(); + } + _ => result = dir::TransitProcessResult::Abort, + }; + result + }; + + result = copy_items_with_progress(&from_paths, &path_to, &options, func_test).unwrap(); + } + assert_eq!(5, count_exist_files); + + assert_eq!(40, result); + assert!(dir1.0.exists()); + assert!(dir1.1.exists()); + assert!(dir2.0.exists()); + assert!(dir2.1.exists()); + assert!(compare_dir(&dir1.0, &path_to)); + assert!(compare_dir(&dir2.0, &path_to)); + assert!(files_eq(&file1.0, &file1.1)); + assert!(files_eq(&file2.0, &file2.1)); + }) + .join(); + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } + rx.try_recv().unwrap(); +} + +#[test] +fn it_copy_with_progress_exist_user_decide_overwrite_all() { + let test_dir = + Path::new(TEST_FOLDER).join("it_copy_with_progress_exist_user_decide_overwrite_all"); + let path_to = test_dir.join("out"); + let dir1 = (test_dir.join("dir1"), path_to.join("dir1")); + let dir2 = (test_dir.join("dir2"), path_to.join("dir2")); + let sub = (dir1.0.join("sub"), dir1.1.join("sub")); + let file1 = (test_dir.join("file1.txt"), path_to.join("file1.txt")); + let file2 = (test_dir.join("file2.txt"), path_to.join("file2.txt")); + let file3 = (dir1.0.join("file3.txt"), dir1.1.join("file3.txt")); + let file4 = (sub.0.join("file4.txt"), sub.1.join("file4.txt")); + let file5 = (dir2.0.join("file5.txt"), dir2.1.join("file5.txt")); + + dir::create_all(&dir1.0, true).unwrap(); + dir::create_all(&dir1.1, true).unwrap(); + dir::create_all(&dir2.0, true).unwrap(); + dir::create_all(&dir2.1, true).unwrap(); + dir::create_all(&sub.0, true).unwrap(); + dir::create_all(&sub.1, true).unwrap(); + + assert!(&dir1.0.exists()); + assert!(&dir1.1.exists()); + assert!(&dir2.0.exists()); + assert!(&dir2.1.exists()); + assert!(&sub.0.exists()); + assert!(&sub.1.exists()); + + fs_extra::file::write_all(&file1.0, "content1").unwrap(); + fs_extra::file::write_all(&file2.0, "content2").unwrap(); + fs_extra::file::write_all(&file3.0, "content3").unwrap(); + fs_extra::file::write_all(&file4.0, "content4").unwrap(); + fs_extra::file::write_all(&file5.0, "content5").unwrap(); + + fs_extra::file::write_all(&file1.1, "old content11").unwrap(); + fs_extra::file::write_all(&file2.1, "old content12").unwrap(); + fs_extra::file::write_all(&file3.1, "old content13").unwrap(); + fs_extra::file::write_all(&file4.1, "old content14").unwrap(); + fs_extra::file::write_all(&file5.1, "old content15").unwrap(); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file3.0.exists()); + assert!(file4.0.exists()); + assert!(file5.0.exists()); + assert!(file1.1.exists()); + assert!(file2.1.exists()); + assert!(file3.1.exists()); + assert!(file4.1.exists()); + assert!(file5.1.exists()); + + let mut options = dir::CopyOptions::new(); + assert!(!compare_dir(&dir1.0, &dir1.1)); + assert!(!compare_dir(&dir2.0, &dir2.1)); + assert!(!files_eq(&file1.0, &file1.1)); + assert!(!files_eq(&file2.0, &file2.1)); + options.buffer_size = 1; + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let mut count_exist_files = 0; + let mut from_paths = Vec::new(); + from_paths.push(dir1.0.as_path()); + from_paths.push(dir2.0.as_path()); + from_paths.push(file1.0.as_path()); + from_paths.push(file2.0.as_path()); + + let result: u64; + { + let func_test = |process_info: TransitProcess| { + let result: dir::TransitProcessResult; + match process_info.state { + dir::TransitState::Exists => { + count_exist_files += 1; + result = dir::TransitProcessResult::OverwriteAll; + tx.send(process_info).unwrap(); + } + _ => result = dir::TransitProcessResult::Abort, + }; + result + }; + + result = copy_items_with_progress(&from_paths, &path_to, &options, func_test).unwrap(); + } + assert_eq!(1, count_exist_files); + + assert_eq!(40, result); + assert!(dir1.0.exists()); + assert!(dir1.1.exists()); + assert!(dir2.0.exists()); + assert!(dir2.1.exists()); + assert!(compare_dir(&dir1.0, &path_to)); + assert!(compare_dir(&dir2.0, &path_to)); + assert!(files_eq(&file1.0, &file1.1)); + assert!(files_eq(&file2.0, &file2.1)); + }) + .join(); + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } + rx.try_recv().unwrap(); +} + +#[test] +fn it_copy_with_progress_exist_user_decide_skip() { + let test_dir = Path::new(TEST_FOLDER).join("it_copy_with_progress_exist_user_decide_skip"); + let path_to = test_dir.join("out"); + let dir1 = (test_dir.join("dir1"), path_to.join("dir1")); + let dir2 = (test_dir.join("dir2"), path_to.join("dir2")); + let sub = (dir1.0.join("sub"), dir1.1.join("sub")); + let file1 = (test_dir.join("file1.txt"), path_to.join("file1.txt")); + let file2 = (test_dir.join("file2.txt"), path_to.join("file2.txt")); + let file3 = (dir1.0.join("file3.txt"), dir1.1.join("file3.txt")); + let file4 = (sub.0.join("file4.txt"), sub.1.join("file4.txt")); + let file5 = (dir2.0.join("file5.txt"), dir2.1.join("file5.txt")); + + dir::create_all(&dir1.0, true).unwrap(); + dir::create_all(&dir1.1, true).unwrap(); + dir::create_all(&dir2.0, true).unwrap(); + dir::create_all(&dir2.1, true).unwrap(); + dir::create_all(&sub.0, true).unwrap(); + dir::create_all(&sub.1, true).unwrap(); + + assert!(&dir1.0.exists()); + assert!(&dir1.1.exists()); + assert!(&dir2.0.exists()); + assert!(&dir2.1.exists()); + assert!(&sub.0.exists()); + assert!(&sub.1.exists()); + + fs_extra::file::write_all(&file1.0, "content1").unwrap(); + fs_extra::file::write_all(&file2.0, "content2").unwrap(); + fs_extra::file::write_all(&file3.0, "content3").unwrap(); + fs_extra::file::write_all(&file4.0, "content4").unwrap(); + fs_extra::file::write_all(&file5.0, "content5").unwrap(); + + fs_extra::file::write_all(&file1.1, "old content11").unwrap(); + fs_extra::file::write_all(&file2.1, "old content12").unwrap(); + fs_extra::file::write_all(&file3.1, "old content13").unwrap(); + fs_extra::file::write_all(&file4.1, "old content14").unwrap(); + fs_extra::file::write_all(&file5.1, "old content15").unwrap(); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file3.0.exists()); + assert!(file4.0.exists()); + assert!(file5.0.exists()); + assert!(file1.1.exists()); + assert!(file2.1.exists()); + assert!(file3.1.exists()); + assert!(file4.1.exists()); + assert!(file5.1.exists()); + + let mut options = dir::CopyOptions::new(); + assert!(!compare_dir(&dir1.0, &dir1.1)); + assert!(!compare_dir(&dir2.0, &dir2.1)); + assert!(!files_eq(&file1.0, &file1.1)); + assert!(!files_eq(&file2.0, &file2.1)); + options.buffer_size = 1; + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let mut count_exist_files = 0; + let mut from_paths = Vec::new(); + from_paths.push(dir1.0.as_path()); + from_paths.push(dir2.0.as_path()); + from_paths.push(file1.0.as_path()); + from_paths.push(file2.0.as_path()); + + let result: u64; + { + let func_test = |process_info: TransitProcess| { + let result: dir::TransitProcessResult; + match process_info.state { + dir::TransitState::Exists => { + count_exist_files += 1; + result = dir::TransitProcessResult::Skip; + tx.send(process_info).unwrap(); + } + _ => result = dir::TransitProcessResult::Abort, + }; + result + }; + + result = copy_items_with_progress(&from_paths, &path_to, &options, func_test).unwrap(); + } + assert_eq!(5, count_exist_files); + + assert_eq!(0, result); + assert!(dir1.0.exists()); + assert!(dir1.1.exists()); + assert!(dir2.0.exists()); + assert!(dir2.1.exists()); + assert!(!compare_dir(&dir1.0, &path_to)); + assert!(!compare_dir(&dir2.0, &path_to)); + assert!(!files_eq(&file1.0, &file1.1)); + assert!(!files_eq(&file2.0, &file2.1)); + }) + .join(); + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } + rx.try_recv().unwrap(); +} + +#[test] +fn it_copy_with_progress_exist_user_decide_skip_all() { + let test_dir = Path::new(TEST_FOLDER).join("it_copy_with_progress_exist_user_decide_skip_all"); + let path_to = test_dir.join("out"); + let dir1 = (test_dir.join("dir1"), path_to.join("dir1")); + let dir2 = (test_dir.join("dir2"), path_to.join("dir2")); + let sub = (dir1.0.join("sub"), dir1.1.join("sub")); + let file1 = (test_dir.join("file1.txt"), path_to.join("file1.txt")); + let file2 = (test_dir.join("file2.txt"), path_to.join("file2.txt")); + let file3 = (dir1.0.join("file3.txt"), dir1.1.join("file3.txt")); + let file4 = (sub.0.join("file4.txt"), sub.1.join("file4.txt")); + let file5 = (dir2.0.join("file5.txt"), dir2.1.join("file5.txt")); + + dir::create_all(&dir1.0, true).unwrap(); + dir::create_all(&dir1.1, true).unwrap(); + dir::create_all(&dir2.0, true).unwrap(); + dir::create_all(&dir2.1, true).unwrap(); + dir::create_all(&sub.0, true).unwrap(); + dir::create_all(&sub.1, true).unwrap(); + + assert!(&dir1.0.exists()); + assert!(&dir1.1.exists()); + assert!(&dir2.0.exists()); + assert!(&dir2.1.exists()); + assert!(&sub.0.exists()); + assert!(&sub.1.exists()); + + fs_extra::file::write_all(&file1.0, "content1").unwrap(); + fs_extra::file::write_all(&file2.0, "content2").unwrap(); + fs_extra::file::write_all(&file3.0, "content3").unwrap(); + fs_extra::file::write_all(&file4.0, "content4").unwrap(); + fs_extra::file::write_all(&file5.0, "content5").unwrap(); + + fs_extra::file::write_all(&file1.1, "old content11").unwrap(); + fs_extra::file::write_all(&file2.1, "old content12").unwrap(); + fs_extra::file::write_all(&file3.1, "old content13").unwrap(); + fs_extra::file::write_all(&file4.1, "old content14").unwrap(); + fs_extra::file::write_all(&file5.1, "old content15").unwrap(); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file3.0.exists()); + assert!(file4.0.exists()); + assert!(file5.0.exists()); + assert!(file1.1.exists()); + assert!(file2.1.exists()); + assert!(file3.1.exists()); + assert!(file4.1.exists()); + assert!(file5.1.exists()); + + let mut options = dir::CopyOptions::new(); + assert!(!compare_dir(&dir1.0, &dir1.1)); + assert!(!compare_dir(&dir2.0, &dir2.1)); + assert!(!files_eq(&file1.0, &file1.1)); + assert!(!files_eq(&file2.0, &file2.1)); + options.buffer_size = 1; + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let mut count_exist_files = 0; + let mut from_paths = Vec::new(); + from_paths.push(dir1.0.as_path()); + from_paths.push(dir2.0.as_path()); + from_paths.push(file1.0.as_path()); + from_paths.push(file2.0.as_path()); + + let result: u64; + { + let func_test = |process_info: TransitProcess| { + let result: dir::TransitProcessResult; + match process_info.state { + dir::TransitState::Exists => { + count_exist_files += 1; + result = dir::TransitProcessResult::SkipAll; + tx.send(process_info).unwrap(); + } + _ => result = dir::TransitProcessResult::Abort, + }; + result + }; + + result = copy_items_with_progress(&from_paths, &path_to, &options, func_test).unwrap(); + } + assert_eq!(1, count_exist_files); + + assert_eq!(0, result); + assert!(dir1.0.exists()); + assert!(dir1.1.exists()); + assert!(dir2.0.exists()); + assert!(dir2.1.exists()); + assert!(!compare_dir(&dir1.0, &path_to)); + assert!(!compare_dir(&dir2.0, &path_to)); + assert!(!files_eq(&file1.0, &file1.1)); + assert!(!files_eq(&file2.0, &file2.1)); + }) + .join(); + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } + rx.try_recv().unwrap(); +} + +#[test] +fn it_copy_with_progress_exist_user_decide_retry() { + let test_dir = Path::new(TEST_FOLDER).join("it_copy_with_progress_exist_user_decide_retry"); + let path_to = test_dir.join("out"); + let dir1 = (test_dir.join("dir1"), path_to.join("dir1")); + let dir2 = (test_dir.join("dir2"), path_to.join("dir2")); + let sub = (dir1.0.join("sub"), dir1.1.join("sub")); + let file1 = (test_dir.join("file1.txt"), path_to.join("file1.txt")); + let file2 = (test_dir.join("file2.txt"), path_to.join("file2.txt")); + let file3 = (dir1.0.join("file3.txt"), dir1.1.join("file3.txt")); + let file4 = (sub.0.join("file4.txt"), sub.1.join("file4.txt")); + let file5 = (dir2.0.join("file5.txt"), dir2.1.join("file5.txt")); + + dir::create_all(&dir1.0, true).unwrap(); + dir::create_all(&dir1.1, true).unwrap(); + dir::create_all(&dir2.0, true).unwrap(); + dir::create_all(&dir2.1, true).unwrap(); + dir::create_all(&sub.0, true).unwrap(); + dir::create_all(&sub.1, true).unwrap(); + + assert!(&dir1.0.exists()); + assert!(&dir1.1.exists()); + assert!(&dir2.0.exists()); + assert!(&dir2.1.exists()); + assert!(&sub.0.exists()); + assert!(&sub.1.exists()); + + fs_extra::file::write_all(&file1.0, "content1").unwrap(); + fs_extra::file::write_all(&file2.0, "content2").unwrap(); + fs_extra::file::write_all(&file3.0, "content3").unwrap(); + fs_extra::file::write_all(&file4.0, "content4").unwrap(); + fs_extra::file::write_all(&file5.0, "content5").unwrap(); + + fs_extra::file::write_all(&file1.1, "old content11").unwrap(); + fs_extra::file::write_all(&file2.1, "old content12").unwrap(); + fs_extra::file::write_all(&file3.1, "old content13").unwrap(); + fs_extra::file::write_all(&file4.1, "old content14").unwrap(); + fs_extra::file::write_all(&file5.1, "old content15").unwrap(); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file3.0.exists()); + assert!(file4.0.exists()); + assert!(file5.0.exists()); + assert!(file1.1.exists()); + assert!(file2.1.exists()); + assert!(file3.1.exists()); + assert!(file4.1.exists()); + assert!(file5.1.exists()); + + let mut options = dir::CopyOptions::new(); + assert!(!compare_dir(&dir1.0, &dir1.1)); + assert!(!compare_dir(&dir2.0, &dir2.1)); + assert!(!files_eq(&file1.0, &file1.1)); + assert!(!files_eq(&file2.0, &file2.1)); + options.buffer_size = 1; + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let mut count_exist_files = 0; + let mut from_paths = Vec::new(); + from_paths.push(dir1.0.as_path()); + from_paths.push(dir2.0.as_path()); + from_paths.push(file1.0.as_path()); + from_paths.push(file2.0.as_path()); + + let result: u64; + { + let func_test = |process_info: TransitProcess| { + let result: dir::TransitProcessResult; + match process_info.state { + dir::TransitState::Exists => { + if count_exist_files == 3 || count_exist_files > 6 { + result = dir::TransitProcessResult::Skip; + } else { + result = dir::TransitProcessResult::Retry; + } + + count_exist_files += 1; + tx.send(process_info).unwrap(); + } + _ => result = dir::TransitProcessResult::Abort, + }; + result + }; + + result = copy_items_with_progress(&from_paths, &path_to, &options, func_test).unwrap(); + } + assert_eq!(11, count_exist_files); + + assert_eq!(0, result); + assert!(dir1.0.exists()); + assert!(dir1.1.exists()); + assert!(dir2.0.exists()); + assert!(dir2.1.exists()); + assert!(!compare_dir(&dir1.0, &path_to)); + assert!(!compare_dir(&dir2.0, &path_to)); + assert!(!files_eq(&file1.0, &file1.1)); + assert!(!files_eq(&file2.0, &file2.1)); + }) + .join(); + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } + rx.try_recv().unwrap(); +} + +#[test] +fn it_move_with_progress_exist_user_decide_overwrite() { + let test_dir = Path::new(TEST_FOLDER).join("it_move_with_progress_exist_user_decide_overwrite"); + let path_to = test_dir.join("out"); + let dir1 = (test_dir.join("dir1"), path_to.join("dir1")); + let dir2 = (test_dir.join("dir2"), path_to.join("dir2")); + let sub = (dir1.0.join("sub"), dir1.1.join("sub")); + let file1 = (test_dir.join("file1.txt"), path_to.join("file1.txt")); + let file2 = (test_dir.join("file2.txt"), path_to.join("file2.txt")); + let file3 = (dir1.0.join("file3.txt"), dir1.1.join("file3.txt")); + let file4 = (sub.0.join("file4.txt"), sub.1.join("file4.txt")); + let file5 = (dir2.0.join("file5.txt"), dir2.1.join("file5.txt")); + + dir::create_all(&dir1.0, true).unwrap(); + dir::create_all(&dir1.1, true).unwrap(); + dir::create_all(&dir2.0, true).unwrap(); + dir::create_all(&dir2.1, true).unwrap(); + dir::create_all(&sub.0, true).unwrap(); + dir::create_all(&sub.1, true).unwrap(); + + assert!(&dir1.0.exists()); + assert!(&dir1.1.exists()); + assert!(&dir2.0.exists()); + assert!(&dir2.1.exists()); + assert!(&sub.0.exists()); + assert!(&sub.1.exists()); + + fs_extra::file::write_all(&file1.0, "content1").unwrap(); + fs_extra::file::write_all(&file2.0, "content2").unwrap(); + fs_extra::file::write_all(&file3.0, "content3").unwrap(); + fs_extra::file::write_all(&file4.0, "content4").unwrap(); + fs_extra::file::write_all(&file5.0, "content5").unwrap(); + + fs_extra::file::write_all(&file1.1, "old content11").unwrap(); + fs_extra::file::write_all(&file2.1, "old content12").unwrap(); + fs_extra::file::write_all(&file3.1, "old content13").unwrap(); + fs_extra::file::write_all(&file4.1, "old content14").unwrap(); + fs_extra::file::write_all(&file5.1, "old content15").unwrap(); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file3.0.exists()); + assert!(file4.0.exists()); + assert!(file5.0.exists()); + assert!(file1.1.exists()); + assert!(file2.1.exists()); + assert!(file3.1.exists()); + assert!(file4.1.exists()); + assert!(file5.1.exists()); + + let mut options = dir::CopyOptions::new(); + assert!(!compare_dir(&dir1.0, &dir1.1)); + assert!(!compare_dir(&dir2.0, &dir2.1)); + assert!(!files_eq(&file1.0, &file1.1)); + assert!(!files_eq(&file2.0, &file2.1)); + options.buffer_size = 1; + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let mut count_exist_files = 0; + let mut from_paths = Vec::new(); + from_paths.push(dir1.0.as_path()); + from_paths.push(dir2.0.as_path()); + from_paths.push(file1.0.as_path()); + from_paths.push(file2.0.as_path()); + + let result: u64; + { + let func_test = |process_info: TransitProcess| { + let result: dir::TransitProcessResult; + match process_info.state { + dir::TransitState::Exists => { + count_exist_files += 1; + result = dir::TransitProcessResult::Overwrite; + tx.send(process_info).unwrap(); + } + _ => result = dir::TransitProcessResult::Abort, + }; + result + }; + + result = move_items_with_progress(&from_paths, &path_to, &options, func_test).unwrap(); + } + assert_eq!(5, count_exist_files); + + assert_eq!(40, result); + assert!(!dir1.0.exists()); + assert!(!dir2.0.exists()); + assert!(dir1.1.exists()); + assert!(dir2.1.exists()); + }) + .join(); + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } + rx.try_recv().unwrap(); +} + +#[test] +fn it_move_with_progress_exist_user_decide_overwrite_all() { + let test_dir = + Path::new(TEST_FOLDER).join("it_move_with_progress_exist_user_decide_overwrite_all"); + let path_to = test_dir.join("out"); + let dir1 = (test_dir.join("dir1"), path_to.join("dir1")); + let dir2 = (test_dir.join("dir2"), path_to.join("dir2")); + let sub = (dir1.0.join("sub"), dir1.1.join("sub")); + let file1 = (test_dir.join("file1.txt"), path_to.join("file1.txt")); + let file2 = (test_dir.join("file2.txt"), path_to.join("file2.txt")); + let file3 = (dir1.0.join("file3.txt"), dir1.1.join("file3.txt")); + let file4 = (sub.0.join("file4.txt"), sub.1.join("file4.txt")); + let file5 = (dir2.0.join("file5.txt"), dir2.1.join("file5.txt")); + + dir::create_all(&dir1.0, true).unwrap(); + dir::create_all(&dir1.1, true).unwrap(); + dir::create_all(&dir2.0, true).unwrap(); + dir::create_all(&dir2.1, true).unwrap(); + dir::create_all(&sub.0, true).unwrap(); + dir::create_all(&sub.1, true).unwrap(); + + assert!(&dir1.0.exists()); + assert!(&dir1.1.exists()); + assert!(&dir2.0.exists()); + assert!(&dir2.1.exists()); + assert!(&sub.0.exists()); + assert!(&sub.1.exists()); + + fs_extra::file::write_all(&file1.0, "content1").unwrap(); + fs_extra::file::write_all(&file2.0, "content2").unwrap(); + fs_extra::file::write_all(&file3.0, "content3").unwrap(); + fs_extra::file::write_all(&file4.0, "content4").unwrap(); + fs_extra::file::write_all(&file5.0, "content5").unwrap(); + + fs_extra::file::write_all(&file1.1, "old content11").unwrap(); + fs_extra::file::write_all(&file2.1, "old content12").unwrap(); + fs_extra::file::write_all(&file3.1, "old content13").unwrap(); + fs_extra::file::write_all(&file4.1, "old content14").unwrap(); + fs_extra::file::write_all(&file5.1, "old content15").unwrap(); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file3.0.exists()); + assert!(file4.0.exists()); + assert!(file5.0.exists()); + assert!(file1.1.exists()); + assert!(file2.1.exists()); + assert!(file3.1.exists()); + assert!(file4.1.exists()); + assert!(file5.1.exists()); + + let mut options = dir::CopyOptions::new(); + assert!(!compare_dir(&dir1.0, &dir1.1)); + assert!(!compare_dir(&dir2.0, &dir2.1)); + assert!(!files_eq(&file1.0, &file1.1)); + assert!(!files_eq(&file2.0, &file2.1)); + options.buffer_size = 1; + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let mut count_exist_files = 0; + let mut from_paths = Vec::new(); + from_paths.push(dir1.0.as_path()); + from_paths.push(dir2.0.as_path()); + from_paths.push(file1.0.as_path()); + from_paths.push(file2.0.as_path()); + + let result: u64; + { + let func_test = |process_info: TransitProcess| { + let result: dir::TransitProcessResult; + match process_info.state { + dir::TransitState::Exists => { + count_exist_files += 1; + result = dir::TransitProcessResult::OverwriteAll; + tx.send(process_info).unwrap(); + } + _ => result = dir::TransitProcessResult::Abort, + }; + result + }; + + result = move_items_with_progress(&from_paths, &path_to, &options, func_test).unwrap(); + } + assert_eq!(1, count_exist_files); + + assert_eq!(40, result); + assert!(!dir1.0.exists()); + assert!(!dir2.0.exists()); + assert!(dir1.1.exists()); + assert!(dir2.1.exists()); + }) + .join(); + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } + rx.try_recv().unwrap(); +} + +#[test] +fn it_move_with_progress_exist_user_decide_skip() { + let test_dir = Path::new(TEST_FOLDER).join("it_move_with_progress_exist_user_decide_skip"); + let path_to = test_dir.join("out"); + let dir1 = (test_dir.join("dir1"), path_to.join("dir1")); + let dir2 = (test_dir.join("dir2"), path_to.join("dir2")); + let sub = (dir1.0.join("sub"), dir1.1.join("sub")); + let file1 = (test_dir.join("file1.txt"), path_to.join("file1.txt")); + let file2 = (test_dir.join("file2.txt"), path_to.join("file2.txt")); + let file3 = (dir1.0.join("file3.txt"), dir1.1.join("file3.txt")); + let file4 = (sub.0.join("file4.txt"), sub.1.join("file4.txt")); + let file5 = (dir2.0.join("file5.txt"), dir2.1.join("file5.txt")); + + dir::create_all(&dir1.0, true).unwrap(); + dir::create_all(&dir1.1, true).unwrap(); + dir::create_all(&dir2.0, true).unwrap(); + dir::create_all(&dir2.1, true).unwrap(); + dir::create_all(&sub.0, true).unwrap(); + dir::create_all(&sub.1, true).unwrap(); + + assert!(&dir1.0.exists()); + assert!(&dir1.1.exists()); + assert!(&dir2.0.exists()); + assert!(&dir2.1.exists()); + assert!(&sub.0.exists()); + assert!(&sub.1.exists()); + + fs_extra::file::write_all(&file1.0, "content1").unwrap(); + fs_extra::file::write_all(&file2.0, "content2").unwrap(); + fs_extra::file::write_all(&file3.0, "content3").unwrap(); + fs_extra::file::write_all(&file4.0, "content4").unwrap(); + fs_extra::file::write_all(&file5.0, "content5").unwrap(); + + fs_extra::file::write_all(&file1.1, "old content11").unwrap(); + fs_extra::file::write_all(&file2.1, "old content12").unwrap(); + fs_extra::file::write_all(&file3.1, "old content13").unwrap(); + fs_extra::file::write_all(&file4.1, "old content14").unwrap(); + fs_extra::file::write_all(&file5.1, "old content15").unwrap(); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file3.0.exists()); + assert!(file4.0.exists()); + assert!(file5.0.exists()); + assert!(file1.1.exists()); + assert!(file2.1.exists()); + assert!(file3.1.exists()); + assert!(file4.1.exists()); + assert!(file5.1.exists()); + + let mut options = dir::CopyOptions::new(); + assert!(!compare_dir(&dir1.0, &dir1.1)); + assert!(!compare_dir(&dir2.0, &dir2.1)); + assert!(!files_eq(&file1.0, &file1.1)); + assert!(!files_eq(&file2.0, &file2.1)); + options.buffer_size = 1; + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let mut count_exist_files = 0; + let mut from_paths = Vec::new(); + from_paths.push(dir1.0.as_path()); + from_paths.push(dir2.0.as_path()); + from_paths.push(file1.0.as_path()); + from_paths.push(file2.0.as_path()); + + let result: u64; + { + let func_test = |process_info: TransitProcess| { + let result: dir::TransitProcessResult; + match process_info.state { + dir::TransitState::Exists => { + count_exist_files += 1; + result = dir::TransitProcessResult::Skip; + tx.send(process_info).unwrap(); + } + _ => result = dir::TransitProcessResult::Abort, + }; + result + }; + + result = move_items_with_progress(&from_paths, &path_to, &options, func_test).unwrap(); + } + assert_eq!(5, count_exist_files); + + assert_eq!(0, result); + assert!(dir1.0.exists()); + assert!(dir2.0.exists()); + assert!(dir1.1.exists()); + assert!(dir2.1.exists()); + }) + .join(); + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } + rx.try_recv().unwrap(); +} + +#[test] +fn it_move_with_progress_exist_user_decide_skip_all() { + let test_dir = Path::new(TEST_FOLDER).join("it_move_with_progress_exist_user_decide_skip_all"); + let path_to = test_dir.join("out"); + let dir1 = (test_dir.join("dir1"), path_to.join("dir1")); + let dir2 = (test_dir.join("dir2"), path_to.join("dir2")); + let sub = (dir1.0.join("sub"), dir1.1.join("sub")); + let file1 = (test_dir.join("file1.txt"), path_to.join("file1.txt")); + let file2 = (test_dir.join("file2.txt"), path_to.join("file2.txt")); + let file3 = (dir1.0.join("file3.txt"), dir1.1.join("file3.txt")); + let file4 = (sub.0.join("file4.txt"), sub.1.join("file4.txt")); + let file5 = (dir2.0.join("file5.txt"), dir2.1.join("file5.txt")); + + dir::create_all(&dir1.0, true).unwrap(); + dir::create_all(&dir1.1, true).unwrap(); + dir::create_all(&dir2.0, true).unwrap(); + dir::create_all(&dir2.1, true).unwrap(); + dir::create_all(&sub.0, true).unwrap(); + dir::create_all(&sub.1, true).unwrap(); + + assert!(&dir1.0.exists()); + assert!(&dir1.1.exists()); + assert!(&dir2.0.exists()); + assert!(&dir2.1.exists()); + assert!(&sub.0.exists()); + assert!(&sub.1.exists()); + + fs_extra::file::write_all(&file1.0, "content1").unwrap(); + fs_extra::file::write_all(&file2.0, "content2").unwrap(); + fs_extra::file::write_all(&file3.0, "content3").unwrap(); + fs_extra::file::write_all(&file4.0, "content4").unwrap(); + fs_extra::file::write_all(&file5.0, "content5").unwrap(); + + fs_extra::file::write_all(&file1.1, "old content11").unwrap(); + fs_extra::file::write_all(&file2.1, "old content12").unwrap(); + fs_extra::file::write_all(&file3.1, "old content13").unwrap(); + fs_extra::file::write_all(&file4.1, "old content14").unwrap(); + fs_extra::file::write_all(&file5.1, "old content15").unwrap(); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file3.0.exists()); + assert!(file4.0.exists()); + assert!(file5.0.exists()); + assert!(file1.1.exists()); + assert!(file2.1.exists()); + assert!(file3.1.exists()); + assert!(file4.1.exists()); + assert!(file5.1.exists()); + + let mut options = dir::CopyOptions::new(); + assert!(!compare_dir(&dir1.0, &dir1.1)); + assert!(!compare_dir(&dir2.0, &dir2.1)); + assert!(!files_eq(&file1.0, &file1.1)); + assert!(!files_eq(&file2.0, &file2.1)); + options.buffer_size = 1; + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let mut count_exist_files = 0; + let mut from_paths = Vec::new(); + from_paths.push(dir1.0.as_path()); + from_paths.push(dir2.0.as_path()); + from_paths.push(file1.0.as_path()); + from_paths.push(file2.0.as_path()); + + let result: u64; + { + let func_test = |process_info: TransitProcess| { + let result: dir::TransitProcessResult; + match process_info.state { + dir::TransitState::Exists => { + count_exist_files += 1; + result = dir::TransitProcessResult::SkipAll; + tx.send(process_info).unwrap(); + } + _ => result = dir::TransitProcessResult::Abort, + }; + result + }; + + result = move_items_with_progress(&from_paths, &path_to, &options, func_test).unwrap(); + } + assert_eq!(1, count_exist_files); + + assert_eq!(0, result); + assert!(dir1.0.exists()); + assert!(dir2.0.exists()); + assert!(dir1.1.exists()); + assert!(dir2.1.exists()); + assert!(file1.0.exists()); + assert!(file2.0.exists()); + }) + .join(); + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } + rx.try_recv().unwrap(); +} + +#[test] +fn it_move_with_progress_exist_user_decide_retry() { + let test_dir = Path::new(TEST_FOLDER).join("it_move_with_progress_exist_user_decide_retry"); + let path_to = test_dir.join("out"); + let dir1 = (test_dir.join("dir1"), path_to.join("dir1")); + let dir2 = (test_dir.join("dir2"), path_to.join("dir2")); + let sub = (dir1.0.join("sub"), dir1.1.join("sub")); + let file1 = (test_dir.join("file1.txt"), path_to.join("file1.txt")); + let file2 = (test_dir.join("file2.txt"), path_to.join("file2.txt")); + let file3 = (dir1.0.join("file3.txt"), dir1.1.join("file3.txt")); + let file4 = (sub.0.join("file4.txt"), sub.1.join("file4.txt")); + let file5 = (dir2.0.join("file5.txt"), dir2.1.join("file5.txt")); + + dir::create_all(&dir1.0, true).unwrap(); + dir::create_all(&dir1.1, true).unwrap(); + dir::create_all(&dir2.0, true).unwrap(); + dir::create_all(&dir2.1, true).unwrap(); + dir::create_all(&sub.0, true).unwrap(); + dir::create_all(&sub.1, true).unwrap(); + + assert!(&dir1.0.exists()); + assert!(&dir1.1.exists()); + assert!(&dir2.0.exists()); + assert!(&dir2.1.exists()); + assert!(&sub.0.exists()); + assert!(&sub.1.exists()); + + fs_extra::file::write_all(&file1.0, "content1").unwrap(); + fs_extra::file::write_all(&file2.0, "content2").unwrap(); + fs_extra::file::write_all(&file3.0, "content3").unwrap(); + fs_extra::file::write_all(&file4.0, "content4").unwrap(); + fs_extra::file::write_all(&file5.0, "content5").unwrap(); + + fs_extra::file::write_all(&file1.1, "old content11").unwrap(); + fs_extra::file::write_all(&file2.1, "old content12").unwrap(); + fs_extra::file::write_all(&file3.1, "old content13").unwrap(); + fs_extra::file::write_all(&file4.1, "old content14").unwrap(); + fs_extra::file::write_all(&file5.1, "old content15").unwrap(); + + assert!(file1.0.exists()); + assert!(file2.0.exists()); + assert!(file3.0.exists()); + assert!(file4.0.exists()); + assert!(file5.0.exists()); + assert!(file1.1.exists()); + assert!(file2.1.exists()); + assert!(file3.1.exists()); + assert!(file4.1.exists()); + assert!(file5.1.exists()); + + let mut options = dir::CopyOptions::new(); + assert!(!compare_dir(&dir1.0, &dir1.1)); + assert!(!compare_dir(&dir2.0, &dir2.1)); + assert!(!files_eq(&file1.0, &file1.1)); + assert!(!files_eq(&file2.0, &file2.1)); + options.buffer_size = 1; + let (tx, rx) = mpsc::channel(); + let result = thread::spawn(move || { + let mut count_exist_files = 0; + let mut from_paths = Vec::new(); + from_paths.push(dir1.0.as_path()); + from_paths.push(dir2.0.as_path()); + from_paths.push(file1.0.as_path()); + from_paths.push(file2.0.as_path()); + + let result: u64; + { + let func_test = |process_info: TransitProcess| { + let result: dir::TransitProcessResult; + match process_info.state { + dir::TransitState::Exists => { + if count_exist_files == 3 || count_exist_files > 6 { + result = dir::TransitProcessResult::Skip; + } else { + result = dir::TransitProcessResult::Retry; + } + + count_exist_files += 1; + tx.send(process_info).unwrap(); + } + _ => result = dir::TransitProcessResult::Abort, + }; + result + }; + + result = move_items_with_progress(&from_paths, &path_to, &options, func_test).unwrap(); + } + assert_eq!(11, count_exist_files); + + assert_eq!(0, result); + assert!(dir1.0.exists()); + assert!(dir2.0.exists()); + assert!(dir1.1.exists()); + assert!(dir2.1.exists()); + }) + .join(); + + match result { + Ok(_) => {} + Err(err) => panic!(err), + } + rx.try_recv().unwrap(); +} -- cgit v1.2.3