1
1
use std:: io:: { Error , Result , ErrorKind } ;
2
- use std:: path:: { PathBuf } ;
2
+ use std:: path:: PathBuf ;
3
3
use std:: fs;
4
4
5
5
/// Recursively copies the contents of the directory `src` to the directory `dst`.
6
- /// Analogous to `cp -rf src/* dst`.
6
+ /// Analogous to `cp -rf src/* dst` and Python's `shutil.copytree`
7
7
pub ( crate ) fn copy_dir_all < S : Into < PathBuf > , D : Into < PathBuf > > ( src : S , dst : D ) -> Result < ( ) > {
8
8
copy_dir_mono ( src. into ( ) , dst. into ( ) )
9
9
}
10
10
11
- /// Monomorphized version of `copy_dir`
11
+ /// Helper for `copy_dir`
12
12
fn copy_dir_mono ( src : PathBuf , dst : PathBuf ) -> Result < ( ) > {
13
13
let mut dirs: Vec < ( PathBuf , PathBuf ) > = Vec :: default ( ) ;
14
14
@@ -31,7 +31,7 @@ fn copy_dir_mono(src: PathBuf, dst: PathBuf) -> Result<()> {
31
31
for entry in src. read_dir ( ) ? {
32
32
let entry = entry?;
33
33
let file_type = entry. file_type ( ) ?;
34
- let src_filename = dbg ! ( entry. file_name( ) ) ;
34
+ let src_filename = entry. file_name ( ) ;
35
35
let src = src. join ( & src_filename) ;
36
36
let dst = dst. join ( & src_filename) ;
37
37
if file_type. is_dir ( ) {
@@ -49,20 +49,92 @@ fn copy_dir_mono(src: PathBuf, dst: PathBuf) -> Result<()> {
49
49
mod tests {
50
50
use super :: copy_dir_all;
51
51
use tempfile:: TempDir ;
52
- // use std::fs::{write, read_to_string};
53
- use std:: io:: { Result } ;
52
+ use std:: io:: Result ;
53
+ use std:: path:: Path ;
54
+ use std:: fs;
54
55
55
- #[ test]
56
- fn empty_dir ( ) -> Result < ( ) > {
57
- let src = TempDir :: new ( ) ?;
58
- let dst = TempDir :: new ( ) ?;
56
+ fn create_paths ( root : & Path , paths : & [ & str ] ) -> Result < ( ) > {
57
+ for path in paths {
58
+ let is_directory = path. ends_with ( "/" ) ;
59
+ let path = root. join ( path) ;
60
+ if is_directory {
61
+ fs:: create_dir_all ( & path) ?;
62
+ } else {
63
+ fs:: create_dir_all ( path. parent ( ) . unwrap ( ) ) ?;
64
+ fs:: write ( & path, "" ) ?;
65
+ }
66
+ }
67
+
68
+ Ok ( ( ) )
69
+ }
70
+
71
+ fn verify_paths ( root : & Path , paths : & [ & str ] ) {
72
+ for path in paths {
73
+ let should_create_directory = path. ends_with ( "/" ) ;
74
+ let path = root. join ( path) ;
75
+ if should_create_directory {
76
+ assert ! ( path. is_dir( ) , "expected {path:?} to be directory" ) ;
77
+ } else {
78
+ assert ! ( path. is_file( ) , "expected {path:?} to be a file" ) ;
79
+ }
80
+ }
81
+ }
82
+
83
+ fn run_test ( paths : & [ & str ] ) -> Result < ( ) > {
84
+ let src = TempDir :: with_prefix ( "src" ) ?;
59
85
let src = src. path ( ) ;
86
+ let dst = TempDir :: with_prefix ( "dst" ) ?;
60
87
let dst = dst. path ( ) ;
88
+ create_paths ( src, paths) ?;
89
+ verify_paths ( src, paths) ;
61
90
copy_dir_all ( src, dst) ?;
62
- let mut dst = dst . read_dir ( ) ? ;
63
- assert ! ( dst. next ( ) . is_none ( ) , "we copied nothing into the destination" ) ;
91
+ verify_paths ( src , paths ) ;
92
+ verify_paths ( dst, paths ) ;
64
93
Ok ( ( ) )
65
94
}
66
95
96
+ #[ test]
97
+ fn empty_dir ( ) -> Result < ( ) > {
98
+ run_test ( & [ ] )
99
+ }
100
+
101
+ #[ test]
102
+ fn one_file ( ) -> Result < ( ) > {
103
+ run_test ( & [ "a" ] )
104
+ }
105
+
106
+ #[ test]
107
+ fn directory_no_files ( ) -> Result < ( ) > {
108
+ run_test ( & [ "a/" ] )
109
+ }
110
+
111
+ #[ test]
112
+ fn one_file_directory ( ) -> Result < ( ) > {
113
+ run_test ( & [ "a" , "b/c" ] )
114
+ }
115
+
116
+ #[ test]
117
+ fn nested_directory ( ) -> Result < ( ) > {
118
+ run_test ( & [ "b/c/d/e/f" ] )
119
+ }
120
+
121
+ #[ test]
122
+ fn two_directory ( ) -> Result < ( ) > {
123
+ run_test ( & [ "a/a" , "b/b" ] )
124
+ }
125
+
126
+ #[ test]
127
+ fn two_directory2 ( ) -> Result < ( ) > {
128
+ run_test ( & [ "a/b" , "b/a" ] )
129
+ }
67
130
131
+ #[ test]
132
+ fn directory_with_multiple_files ( ) -> Result < ( ) > {
133
+ run_test ( & [ "a/a" , "a/b" , "a/c" ] )
134
+ }
135
+
136
+ #[ test]
137
+ fn multiple_directories_with_multiple_files ( ) -> Result < ( ) > {
138
+ run_test ( & [ "d/" , "a/a" , "a/b/" , "a/c" , "a/b/c/d" , "b" ] )
139
+ }
68
140
}
0 commit comments