Skip to content
23 changes: 19 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ var fs = new FileSystem();
var current = fs.CurrentDirectory();

//without extension
var current = fs.DirectoryInfo.FromDirectoryName(fs.Directory.GetCurrentDirectory());
var current = fs.DirectoryInfo.New(fs.Directory.GetCurrentDirectory());
```

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

//create a "temp" subdirectory without extension
current.FileSystem.DirectoryInfo.FromDirectoryName(current.FileSystem.Path.Combine(current.FullName, "temp")).Create();
current.FileSystem.DirectoryInfo.New(current.FileSystem.Path.Combine(current.FullName, "temp")).Create();
```

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

//create a "test.txt" file without extension
using (var stream = current.FileSystem.FileInfo.FromFileName(current.FileSystem.Path.Combine(current.FullName, "test.txt")).Create())
using (var stream = current.FileSystem.FileInfo.New(current.FileSystem.Path.Combine(current.FullName, "test.txt")).Create())
stream.Dispose();
```
```

## IDirectoryInfo.CopyTo extension
```csharp
var fs = new FileSystem();
var current = fs.CurrentDirectory();

//source
var source = fs.DirectoryInfo.New(fs.Path.Combine(current.FullName, "SourceDir"));

//destination
var dest = fs.DirectoryInfo.New(fs.Path.Combine(current.FullName, "DestDir"));

//copy
source.CopyTo(dest, recursive: true);
```
76 changes: 76 additions & 0 deletions src/System.IO.Abstractions.Extensions/IDirectoryInfoExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,81 @@ public static IFileInfo File(this IDirectoryInfo info, string name)
{
return info.FileSystem.FileInfo.New(info.FileSystem.Path.Combine(info.FullName, name));
}

/// <summary>
/// Copies this <see cref="IDirectoryInfo"/> instance and its contents to a new path.
/// </summary>
/// <param name="info"></param>
/// <param name="destDirectoryName">The name and path to wich to copy this directory. The destination must not exist.</param>
/// <returns>An <see cref="IDirectoryInfo"/> for the specified path.</returns>
public static IDirectoryInfo CopyTo(this IDirectoryInfo info, string destDirectoryName)
{
return info.CopyTo(destDirectoryName, false);
}

/// <summary>
/// Copies this <see cref="IDirectoryInfo"/> instance and its contents to a new path.
/// </summary>
/// <param name="info"></param>
/// <param name="destDirectoryName">The name and path to wich to copy this directory. The destination must not exist.</param>
/// <param name="recursive"><see langword="true"/> to copy this directory, its subfolders, and all files; otherwise <see langword="false"/>.</param>
/// <returns>An <see cref="IDirectoryInfo"/> for the specified path.</returns>
public static IDirectoryInfo CopyTo(this IDirectoryInfo info, string destDirectoryName, bool recursive)
{
var dest = info.FileSystem.DirectoryInfo.New(destDirectoryName);
return info.CopyTo(dest, recursive);
}

/// <summary>
/// Copies this <see cref="IDirectoryInfo"/> instance and its contents to a new path.
/// </summary>
/// <param name="info"></param>
/// <param name="destDirectory">The <see cref="IDirectoryInfo"/> to wich to copy this directory. The destination must not exist.</param>
/// <returns>An <see cref="IDirectoryInfo"/> for the specified path.</returns>
public static IDirectoryInfo CopyTo(this IDirectoryInfo info, IDirectoryInfo destDirectory)
{
return info.CopyTo(destDirectory, false);
}

/// <summary>
/// Copies this <see cref="IDirectoryInfo"/> instance and its contents to a new path.
/// </summary>
/// <param name="info"></param>
/// <param name="destDirectory">The <see cref="IDirectoryInfo"/> to wich to copy this directory. The destination must not exist.</param>
/// <param name="recursive"><see langword="true"/> to copy this directory, its subfolders, and all files; otherwise <see langword="false"/>.</param>
/// <returns>An <see cref="IDirectoryInfo"/> for the specified path.</returns>
public static IDirectoryInfo CopyTo(this IDirectoryInfo info, IDirectoryInfo destDirectory, bool recursive)
{
info.Refresh();
if (!info.Exists)
{
throw new DirectoryNotFoundException($"Source directory not found: '{info.FullName}'");
}

destDirectory.Refresh();
if (!destDirectory.Exists)
{
destDirectory.Create();
}

var fileSystem = info.FileSystem;
if (recursive)
{
foreach (var directoryInfo in info.EnumerateDirectories())
{
var newDestDirectory = fileSystem.DirectoryInfo.New(fileSystem.Path.Combine(destDirectory.FullName, directoryInfo.Name));
directoryInfo.CopyTo(newDestDirectory, true);
}
}

foreach (var fileInfo in info.EnumerateFiles())
{
var targetFilePath = fileSystem.Path.Combine(destDirectory.FullName, fileInfo.Name);
fileInfo.CopyTo(targetFilePath);
}

destDirectory.Refresh();
return destDirectory;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,5 +57,214 @@ public void File_Extension_Test()
created.Delete();
Assert.IsFalse(fs.File.Exists(expectedPath));
}

[Test]
public void CopyTo_NonRecursiveWithSubfolder_DoesNotCopySubfolder()
{
//arrange
var fs = new FileSystem();
var workingDir = fs.DirectoryInfo.New(fs.Directory.GetCurrentDirectory()).CreateSubdirectory(Guid.NewGuid().ToString());

//create directories
var source = fs.DirectoryInfo.New(fs.Path.Combine(workingDir.FullName, "SourceDir"));
var sourceSubDir = fs.DirectoryInfo.New(fs.Path.Combine(workingDir.FullName, "SourceDir", "SubDir"));
var dest = fs.DirectoryInfo.New(fs.Path.Combine(workingDir.FullName, "DestDir"));

source.Create();
sourceSubDir.Create();

//make sure everything is set up as expected
Assert.IsTrue(fs.Directory.Exists(source.FullName));
Assert.IsTrue(fs.Directory.Exists(sourceSubDir.FullName));
Assert.IsFalse(fs.Directory.Exists(dest.FullName));

//act
var newDest = source.CopyTo(dest.FullName);

var destSubDir = fs.DirectoryInfo.New(fs.Path.Combine(newDest.FullName, "SubDir"));
Assert.IsTrue(fs.Directory.Exists(newDest.FullName));
Assert.IsFalse(fs.Directory.Exists(destSubDir.FullName));

//cleanup
workingDir.Delete(recursive: true);

Assert.IsFalse(fs.File.Exists(workingDir.FullName));
}

[Test]
public void CopyTo_NonRecursiveWithSubfolderWithFiles_DoesNotCopySubfolderAndSubfolderFiles()
{
//arrange
var fs = new FileSystem();
var workingDir = fs.DirectoryInfo.New(fs.Directory.GetCurrentDirectory()).CreateSubdirectory(Guid.NewGuid().ToString());

//create directories
var source = fs.DirectoryInfo.New(fs.Path.Combine(workingDir.FullName, "SourceDir"));
var sourceSubDir = fs.DirectoryInfo.New(fs.Path.Combine(workingDir.FullName, "SourceDir", "SubDir"));
var dest = fs.DirectoryInfo.New(fs.Path.Combine(workingDir.FullName, "DestDir"));

source.Create();
sourceSubDir.Create();

//create files
var sourceFile = fs.FileInfo.New(fs.Path.Combine(source.FullName, "file.txt"));
var sourceSubDirFile = fs.FileInfo.New(fs.Path.Combine(sourceSubDir.FullName, "file.txt"));

sourceFile.Create().Dispose();
sourceSubDirFile.Create().Dispose();

//make sure everything is set up as expected
Assert.IsTrue(fs.Directory.Exists(source.FullName));
Assert.IsTrue(fs.Directory.Exists(sourceSubDir.FullName));
Assert.IsTrue(fs.File.Exists(sourceFile.FullName));
Assert.IsTrue(fs.File.Exists(sourceSubDirFile.FullName));
Assert.IsFalse(fs.Directory.Exists(dest.FullName));

//act
var newDest = source.CopyTo(dest.FullName);

var destFile = fs.FileInfo.New(fs.Path.Combine(newDest.FullName, "file.txt"));
var destSubDir = fs.DirectoryInfo.New(fs.Path.Combine(newDest.FullName, "SubDir"));
var destSubDirFile = fs.FileInfo.New(fs.Path.Combine(destSubDir.FullName, "file.txt"));
Assert.IsTrue(fs.Directory.Exists(newDest.FullName));
Assert.IsTrue(fs.File.Exists(destFile.FullName));
Assert.IsFalse(fs.Directory.Exists(destSubDir.FullName));
Assert.IsFalse(fs.File.Exists(destSubDirFile.FullName));

//cleanup
workingDir.Delete(recursive: true);

Assert.IsFalse(fs.File.Exists(workingDir.FullName));
}

[Test]
public void CopyTo_RecursiveWithSubfolder_DoesCopySubfolder()
{
//arrange
var fs = new FileSystem();
var workingDir = fs.DirectoryInfo.New(fs.Directory.GetCurrentDirectory()).CreateSubdirectory(Guid.NewGuid().ToString());

//create directories
var source = fs.DirectoryInfo.New(fs.Path.Combine(workingDir.FullName, "SourceDir"));
var sourceSubDir = fs.DirectoryInfo.New(fs.Path.Combine(source.FullName, "SubDir"));
var dest = fs.DirectoryInfo.New(fs.Path.Combine(workingDir.FullName, "DestDir"));

source.Create();
sourceSubDir.Create();

//make sure everything is set up as expected
Assert.IsTrue(fs.Directory.Exists(source.FullName));
Assert.IsTrue(fs.Directory.Exists(sourceSubDir.FullName));
Assert.IsFalse(fs.Directory.Exists(dest.FullName));

//act
var newDest = source.CopyTo(dest.FullName, recursive: true);

var destSubDir = fs.DirectoryInfo.New(fs.Path.Combine(newDest.FullName, "SubDir"));
Assert.IsTrue(fs.Directory.Exists(newDest.FullName));
Assert.IsTrue(fs.Directory.Exists(destSubDir.FullName));

//cleanup
workingDir.Delete(recursive: true);

Assert.IsFalse(fs.File.Exists(workingDir.FullName));
}

[Test]
public void CopyTo_RecursiveWithSubfolderWithFiles_DoesCopySubfolderAndSubfolderFiles()
{
//arrange
var fs = new FileSystem();
var workingDir = fs.DirectoryInfo.New(fs.Directory.GetCurrentDirectory()).CreateSubdirectory(Guid.NewGuid().ToString());

//create directories
var source = fs.DirectoryInfo.New(fs.Path.Combine(workingDir.FullName, "SourceDir"));
var sourceSubDir = fs.DirectoryInfo.New(fs.Path.Combine(source.FullName, "SubDir"));
var dest = fs.DirectoryInfo.New(fs.Path.Combine(workingDir.FullName, "DestDir"));

source.Create();
sourceSubDir.Create();

//create files
var sourceFile = fs.FileInfo.New(fs.Path.Combine(source.FullName, "file.txt"));
var sourceSubDirFile = fs.FileInfo.New(fs.Path.Combine(sourceSubDir.FullName, "file.txt"));

sourceFile.Create().Dispose();
sourceSubDirFile.Create().Dispose();

//make sure everything is set up as expected
Assert.IsTrue(fs.Directory.Exists(source.FullName));
Assert.IsTrue(fs.Directory.Exists(sourceSubDir.FullName));
Assert.IsTrue(fs.File.Exists(sourceFile.FullName));
Assert.IsTrue(fs.File.Exists(sourceSubDirFile.FullName));
Assert.IsFalse(fs.Directory.Exists(dest.FullName));

//act
var newDest = source.CopyTo(dest.FullName, recursive: true);

var destFile = fs.FileInfo.New(fs.Path.Combine(newDest.FullName, "file.txt"));
var destSubDir = fs.DirectoryInfo.New(fs.Path.Combine(newDest.FullName, "SubDir"));
var destSubDirFile = fs.FileInfo.New(fs.Path.Combine(destSubDir.FullName, "file.txt"));
Assert.IsTrue(fs.Directory.Exists(newDest.FullName));
Assert.IsTrue(fs.File.Exists(destFile.FullName));
Assert.IsTrue(fs.Directory.Exists(destSubDir.FullName));
Assert.IsTrue(fs.File.Exists(destSubDirFile.FullName));

//cleanup
workingDir.Delete(recursive: true);

Assert.IsFalse(fs.File.Exists(workingDir.FullName));
}

[Test]
public void CopyTo_SourceDirDoesNotExists_ThrowsDirectoryNotFoundException()
{
//arrange
var fs = new FileSystem();
var workingDir = fs.DirectoryInfo.New(fs.Directory.GetCurrentDirectory()).CreateSubdirectory(Guid.NewGuid().ToString());

//create directories
var source = fs.DirectoryInfo.New(fs.Path.Combine(workingDir.FullName, "SourceDir"));
var dest = fs.DirectoryInfo.New(fs.Path.Combine(workingDir.FullName, "DestDir"));

//make sure everything is set up as expected
Assert.IsFalse(fs.Directory.Exists(source.FullName));
Assert.IsFalse(fs.Directory.Exists(dest.FullName));

//act
Assert.That(() => source.CopyTo(dest.FullName), Throws.Exception.TypeOf<DirectoryNotFoundException>().And.Message.EqualTo($"Source directory not found: '{source.FullName}'"));

Assert.IsFalse(fs.File.Exists(source.FullName));
Assert.IsFalse(fs.File.Exists(dest.FullName));
}

[Test]
public void CopyTo_TargetDirAndParentDoesNotExist_CreatesTargetDirectoryHierarchy()
{
//arrange
var fs = new FileSystem();
var workingDir = fs.DirectoryInfo.New(fs.Directory.GetCurrentDirectory()).CreateSubdirectory(Guid.NewGuid().ToString());

//create directories
var source = fs.DirectoryInfo.New(fs.Path.Combine(workingDir.FullName, "SourceDir"));
var dest = fs.DirectoryInfo.New(fs.Path.Combine(workingDir.FullName, "ParentDir", "DestDir"));

source.Create();

//make sure everything is set up as expected
Assert.IsTrue(fs.Directory.Exists(source.FullName));
Assert.IsFalse(fs.Directory.Exists(dest.FullName));

//act
source.CopyTo(dest.FullName);

//assert
Assert.IsTrue(fs.Directory.Exists(dest.FullName));

//cleanup
workingDir.Delete(recursive: true);

Assert.IsFalse(fs.File.Exists(workingDir.FullName));
}
}
}