Skip to content

Commit 287f440

Browse files
authored
feat: IDirectoryInfo.CopyTo (#19)
* New Extension Method IDirectoryInfo.CopyTo Added an Extension Method to IDirectoryInfo to recursively copy a directory. * Refactorings and updated xmldoc * Update README.md Added Example for IDirectoryInfo.CopyTo extension * Fixes for Codacy issues * Updated to 17.X Fixed "Deprecated" warings from version 17.X * Update Readme to 17.X Update Readme to 17.X * Implemented Recomendations Reordered Methods. Removed throw if destination exists. Usage of IFileSystem * Adopted Formatting
1 parent db2349e commit 287f440

File tree

3 files changed

+304
-4
lines changed

3 files changed

+304
-4
lines changed

README.md

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ var fs = new FileSystem();
2222
var current = fs.CurrentDirectory();
2323

2424
//without extension
25-
var current = fs.DirectoryInfo.FromDirectoryName(fs.Directory.GetCurrentDirectory());
25+
var current = fs.DirectoryInfo.New(fs.Directory.GetCurrentDirectory());
2626
```
2727

2828
## SubDirectory extension
@@ -34,7 +34,7 @@ var current = new FileSystem().CurrentDirectory();
3434
current.SubDirectory("temp").Create();
3535

3636
//create a "temp" subdirectory without extension
37-
current.FileSystem.DirectoryInfo.FromDirectoryName(current.FileSystem.Path.Combine(current.FullName, "temp")).Create();
37+
current.FileSystem.DirectoryInfo.New(current.FileSystem.Path.Combine(current.FullName, "temp")).Create();
3838
```
3939

4040
## File extension
@@ -47,6 +47,21 @@ using (var stream = current.File("test.txt").Create())
4747
stream.Dispose();
4848

4949
//create a "test.txt" file without extension
50-
using (var stream = current.FileSystem.FileInfo.FromFileName(current.FileSystem.Path.Combine(current.FullName, "test.txt")).Create())
50+
using (var stream = current.FileSystem.FileInfo.New(current.FileSystem.Path.Combine(current.FullName, "test.txt")).Create())
5151
stream.Dispose();
52-
```
52+
```
53+
54+
## IDirectoryInfo.CopyTo extension
55+
```csharp
56+
var fs = new FileSystem();
57+
var current = fs.CurrentDirectory();
58+
59+
//source
60+
var source = fs.DirectoryInfo.New(fs.Path.Combine(current.FullName, "SourceDir"));
61+
62+
//destination
63+
var dest = fs.DirectoryInfo.New(fs.Path.Combine(current.FullName, "DestDir"));
64+
65+
//copy
66+
source.CopyTo(dest, recursive: true);
67+
```

src/System.IO.Abstractions.Extensions/IDirectoryInfoExtensions.cs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,81 @@ public static IFileInfo File(this IDirectoryInfo info, string name)
2323
{
2424
return info.FileSystem.FileInfo.New(info.FileSystem.Path.Combine(info.FullName, name));
2525
}
26+
27+
/// <summary>
28+
/// Copies this <see cref="IDirectoryInfo"/> instance and its contents to a new path.
29+
/// </summary>
30+
/// <param name="info"></param>
31+
/// <param name="destDirectoryName">The name and path to wich to copy this directory. The destination must not exist.</param>
32+
/// <returns>An <see cref="IDirectoryInfo"/> for the specified path.</returns>
33+
public static IDirectoryInfo CopyTo(this IDirectoryInfo info, string destDirectoryName)
34+
{
35+
return info.CopyTo(destDirectoryName, false);
36+
}
37+
38+
/// <summary>
39+
/// Copies this <see cref="IDirectoryInfo"/> instance and its contents to a new path.
40+
/// </summary>
41+
/// <param name="info"></param>
42+
/// <param name="destDirectoryName">The name and path to wich to copy this directory. The destination must not exist.</param>
43+
/// <param name="recursive"><see langword="true"/> to copy this directory, its subfolders, and all files; otherwise <see langword="false"/>.</param>
44+
/// <returns>An <see cref="IDirectoryInfo"/> for the specified path.</returns>
45+
public static IDirectoryInfo CopyTo(this IDirectoryInfo info, string destDirectoryName, bool recursive)
46+
{
47+
var dest = info.FileSystem.DirectoryInfo.New(destDirectoryName);
48+
return info.CopyTo(dest, recursive);
49+
}
50+
51+
/// <summary>
52+
/// Copies this <see cref="IDirectoryInfo"/> instance and its contents to a new path.
53+
/// </summary>
54+
/// <param name="info"></param>
55+
/// <param name="destDirectory">The <see cref="IDirectoryInfo"/> to wich to copy this directory. The destination must not exist.</param>
56+
/// <returns>An <see cref="IDirectoryInfo"/> for the specified path.</returns>
57+
public static IDirectoryInfo CopyTo(this IDirectoryInfo info, IDirectoryInfo destDirectory)
58+
{
59+
return info.CopyTo(destDirectory, false);
60+
}
61+
62+
/// <summary>
63+
/// Copies this <see cref="IDirectoryInfo"/> instance and its contents to a new path.
64+
/// </summary>
65+
/// <param name="info"></param>
66+
/// <param name="destDirectory">The <see cref="IDirectoryInfo"/> to wich to copy this directory. The destination must not exist.</param>
67+
/// <param name="recursive"><see langword="true"/> to copy this directory, its subfolders, and all files; otherwise <see langword="false"/>.</param>
68+
/// <returns>An <see cref="IDirectoryInfo"/> for the specified path.</returns>
69+
public static IDirectoryInfo CopyTo(this IDirectoryInfo info, IDirectoryInfo destDirectory, bool recursive)
70+
{
71+
info.Refresh();
72+
if (!info.Exists)
73+
{
74+
throw new DirectoryNotFoundException($"Source directory not found: '{info.FullName}'");
75+
}
76+
77+
destDirectory.Refresh();
78+
if (!destDirectory.Exists)
79+
{
80+
destDirectory.Create();
81+
}
82+
83+
var fileSystem = info.FileSystem;
84+
if (recursive)
85+
{
86+
foreach (var directoryInfo in info.EnumerateDirectories())
87+
{
88+
var newDestDirectory = fileSystem.DirectoryInfo.New(fileSystem.Path.Combine(destDirectory.FullName, directoryInfo.Name));
89+
directoryInfo.CopyTo(newDestDirectory, true);
90+
}
91+
}
92+
93+
foreach (var fileInfo in info.EnumerateFiles())
94+
{
95+
var targetFilePath = fileSystem.Path.Combine(destDirectory.FullName, fileInfo.Name);
96+
fileInfo.CopyTo(targetFilePath);
97+
}
98+
99+
destDirectory.Refresh();
100+
return destDirectory;
101+
}
26102
}
27103
}

tests/System.IO.Abstractions.Extensions.Tests/DirectoryInfoExtensionsTests.cs

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,5 +57,214 @@ public void File_Extension_Test()
5757
created.Delete();
5858
Assert.IsFalse(fs.File.Exists(expectedPath));
5959
}
60+
61+
[Test]
62+
public void CopyTo_NonRecursiveWithSubfolder_DoesNotCopySubfolder()
63+
{
64+
//arrange
65+
var fs = new FileSystem();
66+
var workingDir = fs.DirectoryInfo.New(fs.Directory.GetCurrentDirectory()).CreateSubdirectory(Guid.NewGuid().ToString());
67+
68+
//create directories
69+
var source = fs.DirectoryInfo.New(fs.Path.Combine(workingDir.FullName, "SourceDir"));
70+
var sourceSubDir = fs.DirectoryInfo.New(fs.Path.Combine(workingDir.FullName, "SourceDir", "SubDir"));
71+
var dest = fs.DirectoryInfo.New(fs.Path.Combine(workingDir.FullName, "DestDir"));
72+
73+
source.Create();
74+
sourceSubDir.Create();
75+
76+
//make sure everything is set up as expected
77+
Assert.IsTrue(fs.Directory.Exists(source.FullName));
78+
Assert.IsTrue(fs.Directory.Exists(sourceSubDir.FullName));
79+
Assert.IsFalse(fs.Directory.Exists(dest.FullName));
80+
81+
//act
82+
var newDest = source.CopyTo(dest.FullName);
83+
84+
var destSubDir = fs.DirectoryInfo.New(fs.Path.Combine(newDest.FullName, "SubDir"));
85+
Assert.IsTrue(fs.Directory.Exists(newDest.FullName));
86+
Assert.IsFalse(fs.Directory.Exists(destSubDir.FullName));
87+
88+
//cleanup
89+
workingDir.Delete(recursive: true);
90+
91+
Assert.IsFalse(fs.File.Exists(workingDir.FullName));
92+
}
93+
94+
[Test]
95+
public void CopyTo_NonRecursiveWithSubfolderWithFiles_DoesNotCopySubfolderAndSubfolderFiles()
96+
{
97+
//arrange
98+
var fs = new FileSystem();
99+
var workingDir = fs.DirectoryInfo.New(fs.Directory.GetCurrentDirectory()).CreateSubdirectory(Guid.NewGuid().ToString());
100+
101+
//create directories
102+
var source = fs.DirectoryInfo.New(fs.Path.Combine(workingDir.FullName, "SourceDir"));
103+
var sourceSubDir = fs.DirectoryInfo.New(fs.Path.Combine(workingDir.FullName, "SourceDir", "SubDir"));
104+
var dest = fs.DirectoryInfo.New(fs.Path.Combine(workingDir.FullName, "DestDir"));
105+
106+
source.Create();
107+
sourceSubDir.Create();
108+
109+
//create files
110+
var sourceFile = fs.FileInfo.New(fs.Path.Combine(source.FullName, "file.txt"));
111+
var sourceSubDirFile = fs.FileInfo.New(fs.Path.Combine(sourceSubDir.FullName, "file.txt"));
112+
113+
sourceFile.Create().Dispose();
114+
sourceSubDirFile.Create().Dispose();
115+
116+
//make sure everything is set up as expected
117+
Assert.IsTrue(fs.Directory.Exists(source.FullName));
118+
Assert.IsTrue(fs.Directory.Exists(sourceSubDir.FullName));
119+
Assert.IsTrue(fs.File.Exists(sourceFile.FullName));
120+
Assert.IsTrue(fs.File.Exists(sourceSubDirFile.FullName));
121+
Assert.IsFalse(fs.Directory.Exists(dest.FullName));
122+
123+
//act
124+
var newDest = source.CopyTo(dest.FullName);
125+
126+
var destFile = fs.FileInfo.New(fs.Path.Combine(newDest.FullName, "file.txt"));
127+
var destSubDir = fs.DirectoryInfo.New(fs.Path.Combine(newDest.FullName, "SubDir"));
128+
var destSubDirFile = fs.FileInfo.New(fs.Path.Combine(destSubDir.FullName, "file.txt"));
129+
Assert.IsTrue(fs.Directory.Exists(newDest.FullName));
130+
Assert.IsTrue(fs.File.Exists(destFile.FullName));
131+
Assert.IsFalse(fs.Directory.Exists(destSubDir.FullName));
132+
Assert.IsFalse(fs.File.Exists(destSubDirFile.FullName));
133+
134+
//cleanup
135+
workingDir.Delete(recursive: true);
136+
137+
Assert.IsFalse(fs.File.Exists(workingDir.FullName));
138+
}
139+
140+
[Test]
141+
public void CopyTo_RecursiveWithSubfolder_DoesCopySubfolder()
142+
{
143+
//arrange
144+
var fs = new FileSystem();
145+
var workingDir = fs.DirectoryInfo.New(fs.Directory.GetCurrentDirectory()).CreateSubdirectory(Guid.NewGuid().ToString());
146+
147+
//create directories
148+
var source = fs.DirectoryInfo.New(fs.Path.Combine(workingDir.FullName, "SourceDir"));
149+
var sourceSubDir = fs.DirectoryInfo.New(fs.Path.Combine(source.FullName, "SubDir"));
150+
var dest = fs.DirectoryInfo.New(fs.Path.Combine(workingDir.FullName, "DestDir"));
151+
152+
source.Create();
153+
sourceSubDir.Create();
154+
155+
//make sure everything is set up as expected
156+
Assert.IsTrue(fs.Directory.Exists(source.FullName));
157+
Assert.IsTrue(fs.Directory.Exists(sourceSubDir.FullName));
158+
Assert.IsFalse(fs.Directory.Exists(dest.FullName));
159+
160+
//act
161+
var newDest = source.CopyTo(dest.FullName, recursive: true);
162+
163+
var destSubDir = fs.DirectoryInfo.New(fs.Path.Combine(newDest.FullName, "SubDir"));
164+
Assert.IsTrue(fs.Directory.Exists(newDest.FullName));
165+
Assert.IsTrue(fs.Directory.Exists(destSubDir.FullName));
166+
167+
//cleanup
168+
workingDir.Delete(recursive: true);
169+
170+
Assert.IsFalse(fs.File.Exists(workingDir.FullName));
171+
}
172+
173+
[Test]
174+
public void CopyTo_RecursiveWithSubfolderWithFiles_DoesCopySubfolderAndSubfolderFiles()
175+
{
176+
//arrange
177+
var fs = new FileSystem();
178+
var workingDir = fs.DirectoryInfo.New(fs.Directory.GetCurrentDirectory()).CreateSubdirectory(Guid.NewGuid().ToString());
179+
180+
//create directories
181+
var source = fs.DirectoryInfo.New(fs.Path.Combine(workingDir.FullName, "SourceDir"));
182+
var sourceSubDir = fs.DirectoryInfo.New(fs.Path.Combine(source.FullName, "SubDir"));
183+
var dest = fs.DirectoryInfo.New(fs.Path.Combine(workingDir.FullName, "DestDir"));
184+
185+
source.Create();
186+
sourceSubDir.Create();
187+
188+
//create files
189+
var sourceFile = fs.FileInfo.New(fs.Path.Combine(source.FullName, "file.txt"));
190+
var sourceSubDirFile = fs.FileInfo.New(fs.Path.Combine(sourceSubDir.FullName, "file.txt"));
191+
192+
sourceFile.Create().Dispose();
193+
sourceSubDirFile.Create().Dispose();
194+
195+
//make sure everything is set up as expected
196+
Assert.IsTrue(fs.Directory.Exists(source.FullName));
197+
Assert.IsTrue(fs.Directory.Exists(sourceSubDir.FullName));
198+
Assert.IsTrue(fs.File.Exists(sourceFile.FullName));
199+
Assert.IsTrue(fs.File.Exists(sourceSubDirFile.FullName));
200+
Assert.IsFalse(fs.Directory.Exists(dest.FullName));
201+
202+
//act
203+
var newDest = source.CopyTo(dest.FullName, recursive: true);
204+
205+
var destFile = fs.FileInfo.New(fs.Path.Combine(newDest.FullName, "file.txt"));
206+
var destSubDir = fs.DirectoryInfo.New(fs.Path.Combine(newDest.FullName, "SubDir"));
207+
var destSubDirFile = fs.FileInfo.New(fs.Path.Combine(destSubDir.FullName, "file.txt"));
208+
Assert.IsTrue(fs.Directory.Exists(newDest.FullName));
209+
Assert.IsTrue(fs.File.Exists(destFile.FullName));
210+
Assert.IsTrue(fs.Directory.Exists(destSubDir.FullName));
211+
Assert.IsTrue(fs.File.Exists(destSubDirFile.FullName));
212+
213+
//cleanup
214+
workingDir.Delete(recursive: true);
215+
216+
Assert.IsFalse(fs.File.Exists(workingDir.FullName));
217+
}
218+
219+
[Test]
220+
public void CopyTo_SourceDirDoesNotExists_ThrowsDirectoryNotFoundException()
221+
{
222+
//arrange
223+
var fs = new FileSystem();
224+
var workingDir = fs.DirectoryInfo.New(fs.Directory.GetCurrentDirectory()).CreateSubdirectory(Guid.NewGuid().ToString());
225+
226+
//create directories
227+
var source = fs.DirectoryInfo.New(fs.Path.Combine(workingDir.FullName, "SourceDir"));
228+
var dest = fs.DirectoryInfo.New(fs.Path.Combine(workingDir.FullName, "DestDir"));
229+
230+
//make sure everything is set up as expected
231+
Assert.IsFalse(fs.Directory.Exists(source.FullName));
232+
Assert.IsFalse(fs.Directory.Exists(dest.FullName));
233+
234+
//act
235+
Assert.That(() => source.CopyTo(dest.FullName), Throws.Exception.TypeOf<DirectoryNotFoundException>().And.Message.EqualTo($"Source directory not found: '{source.FullName}'"));
236+
237+
Assert.IsFalse(fs.File.Exists(source.FullName));
238+
Assert.IsFalse(fs.File.Exists(dest.FullName));
239+
}
240+
241+
[Test]
242+
public void CopyTo_TargetDirAndParentDoesNotExist_CreatesTargetDirectoryHierarchy()
243+
{
244+
//arrange
245+
var fs = new FileSystem();
246+
var workingDir = fs.DirectoryInfo.New(fs.Directory.GetCurrentDirectory()).CreateSubdirectory(Guid.NewGuid().ToString());
247+
248+
//create directories
249+
var source = fs.DirectoryInfo.New(fs.Path.Combine(workingDir.FullName, "SourceDir"));
250+
var dest = fs.DirectoryInfo.New(fs.Path.Combine(workingDir.FullName, "ParentDir", "DestDir"));
251+
252+
source.Create();
253+
254+
//make sure everything is set up as expected
255+
Assert.IsTrue(fs.Directory.Exists(source.FullName));
256+
Assert.IsFalse(fs.Directory.Exists(dest.FullName));
257+
258+
//act
259+
source.CopyTo(dest.FullName);
260+
261+
//assert
262+
Assert.IsTrue(fs.Directory.Exists(dest.FullName));
263+
264+
//cleanup
265+
workingDir.Delete(recursive: true);
266+
267+
Assert.IsFalse(fs.File.Exists(workingDir.FullName));
268+
}
60269
}
61270
}

0 commit comments

Comments
 (0)