Skip to content

Commit 566afec

Browse files
authored
feat: add overwrite option to File.Move and FileInfo.MoveTo (#678)
1 parent bb2a49d commit 566afec

15 files changed

Lines changed: 143 additions & 11 deletions

File tree

Directory.Build.props

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
<PackageProjectUrl>https://github.com/System-IO-Abstractions/System.IO.Abstractions</PackageProjectUrl>
1313
<PackageLicenseExpression>MIT</PackageLicenseExpression>
1414
<DefineConstants Condition="'$(TargetFramework)' == 'net5.0' OR '$(TargetFramework)' == 'netcoreapp3.1' OR '$(TargetFramework)' == 'netstandard2.1'">$(DefineConstants);FEATURE_ASYNC_FILE;FEATURE_ENUMERATION_OPTIONS;FEATURE_ADVANCED_PATH_OPERATIONSFEATURE_PATH_JOIN_WITH_SPAN</DefineConstants>
15+
<DefineConstants Condition="'$(TargetFramework)' == 'net5.0'">$(DefineConstants);FEATURE_FILE_MOVE_WITH_OVERWRITE</DefineConstants>
1516
</PropertyGroup>
1617
<ItemGroup>
1718
<PackageReference Include="Nerdbank.GitVersioning" Version="3.3.37">

src/System.IO.Abstractions.TestingHelpers/MockFile.cs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,52 @@ public override void Move(string sourceFileName, string destFileName)
357357
mockFileDataAccessor.RemoveFile(sourceFileName);
358358
}
359359

360+
#if FEATURE_FILE_MOVE_WITH_OVERWRITE
361+
public override void Move(string sourceFileName, string destFileName, bool overwrite)
362+
{
363+
if (sourceFileName == null)
364+
{
365+
throw CommonExceptions.FilenameCannotBeNull(nameof(sourceFileName));
366+
}
367+
368+
if (destFileName == null)
369+
{
370+
throw CommonExceptions.FilenameCannotBeNull(nameof(destFileName));
371+
}
372+
373+
mockFileDataAccessor.PathVerifier.IsLegalAbsoluteOrRelative(sourceFileName, nameof(sourceFileName));
374+
mockFileDataAccessor.PathVerifier.IsLegalAbsoluteOrRelative(destFileName, nameof(destFileName));
375+
376+
if (mockFileDataAccessor.GetFile(destFileName) != null)
377+
{
378+
if (destFileName.Equals(sourceFileName))
379+
{
380+
return;
381+
}
382+
else if (!overwrite)
383+
{
384+
throw new IOException("A file can not be created if it already exists.");
385+
}
386+
}
387+
388+
389+
var sourceFile = mockFileDataAccessor.GetFile(sourceFileName);
390+
391+
if (sourceFile == null)
392+
{
393+
throw CommonExceptions.FileNotFound(sourceFileName);
394+
}
395+
if (!sourceFile.AllowedFileShare.HasFlag(FileShare.Delete))
396+
{
397+
throw CommonExceptions.ProcessCannotAccessFileInUse();
398+
}
399+
VerifyDirectoryExists(destFileName);
400+
401+
mockFileDataAccessor.AddFile(destFileName, new MockFileData(sourceFile));
402+
mockFileDataAccessor.RemoveFile(sourceFileName);
403+
}
404+
#endif
405+
360406
public override Stream Open(string path, FileMode mode)
361407
{
362408
mockFileDataAccessor.PathVerifier.IsLegalAbsoluteOrRelative(path, "path");

src/System.IO.Abstractions.TestingHelpers/MockFileInfo.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,19 @@ public override void MoveTo(string destFileName)
236236
path = movedFileInfo.FullName;
237237
}
238238

239+
#if FEATURE_FILE_MOVE_WITH_OVERWRITE
240+
public override void MoveTo(string destFileName, bool overwrite)
241+
{
242+
var movedFileInfo = CopyTo(destFileName, overwrite);
243+
if (destFileName == FullName)
244+
{
245+
return;
246+
}
247+
Delete();
248+
path = movedFileInfo.FullName;
249+
}
250+
#endif
251+
239252
public override Stream Open(FileMode mode)
240253
{
241254
return new MockFile(mockFileSystem).Open(FullName, mode);

src/System.IO.Abstractions/FileBase.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,11 @@ internal FileBase() { }
260260
/// <inheritdoc cref="File.Move"/>
261261
public abstract void Move(string sourceFileName, string destFileName);
262262

263+
#if FEATURE_FILE_MOVE_WITH_OVERWRITE
264+
/// <inheritdoc cref="File.Move(string,string,bool)"/>
265+
public abstract void Move(string sourceFileName, string destFileName, bool overwrite);
266+
#endif
267+
263268
/// <inheritdoc cref="File.Open(string,FileMode)"/>
264269
public abstract Stream Open(string path, FileMode mode);
265270

src/System.IO.Abstractions/FileInfoBase.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ internal FileInfoBase() { }
4343
/// <inheritdoc cref="FileInfo.MoveTo"/>
4444
public abstract void MoveTo(string destFileName);
4545

46+
#if FEATURE_FILE_MOVE_WITH_OVERWRITE
47+
/// <inheritdoc cref="FileInfo.MoveTo(string,bool)"/>
48+
public abstract void MoveTo(string destFileName, bool overwrite);
49+
#endif
50+
4651
/// <inheritdoc cref="FileInfo.Open(FileMode)"/>
4752
public abstract Stream Open(FileMode mode);
4853

src/System.IO.Abstractions/FileInfoWrapper.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,13 @@ public override void MoveTo(string destFileName)
134134
instance.MoveTo(destFileName);
135135
}
136136

137+
#if FEATURE_FILE_MOVE_WITH_OVERWRITE
138+
public override void MoveTo(string destFileName, bool overwrite)
139+
{
140+
instance.MoveTo(destFileName, overwrite);
141+
}
142+
#endif
143+
137144
public override Stream Open(FileMode mode)
138145
{
139146
return instance.Open(mode);

src/System.IO.Abstractions/FileWrapper.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,14 @@ public override void Move(string sourceFileName, string destFileName)
149149
File.Move(sourceFileName, destFileName);
150150
}
151151

152+
#if FEATURE_FILE_MOVE_WITH_OVERWRITE
153+
public override void Move(string sourceFileName, string destFileName, bool overwrite)
154+
{
155+
File.Move(sourceFileName, destFileName, overwrite);
156+
}
157+
#endif
158+
159+
152160
public override Stream Open(string path, FileMode mode)
153161
{
154162
return File.Open(path, mode);

src/System.IO.Abstractions/IFile.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,12 @@ public partial interface IFile
6161
DateTime GetLastWriteTime(string path);
6262
/// <inheritdoc cref="File.GetLastWriteTimeUtc"/>
6363
DateTime GetLastWriteTimeUtc(string path);
64-
/// <inheritdoc cref="File.Move"/>
64+
/// <inheritdoc cref="File.Move(string,string)"/>
6565
void Move(string sourceFileName, string destFileName);
66+
#if FEATURE_FILE_MOVE_WITH_OVERWRITE
67+
/// <inheritdoc cref="File.Move(string,string,bool)"/>
68+
void Move(string sourceFileName, string destFileName, bool overwrite);
69+
#endif
6670
/// <inheritdoc cref="File.Open(string,FileMode)"/>
6771
Stream Open(string path, FileMode mode);
6872
/// <inheritdoc cref="File.Open(string,FileMode,FileAccess)"/>

src/System.IO.Abstractions/IFileInfo.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,12 @@ public interface IFileInfo : IFileSystemInfo
2222
FileSecurity GetAccessControl();
2323
/// <inheritdoc cref="FileInfo.GetAccessControl(AccessControlSections)"/>
2424
FileSecurity GetAccessControl(AccessControlSections includeSections);
25-
/// <inheritdoc cref="FileInfo.MoveTo"/>
25+
/// <inheritdoc cref="FileInfo.MoveTo(string)"/>
2626
void MoveTo(string destFileName);
27+
#if FEATURE_FILE_MOVE_WITH_OVERWRITE
28+
/// <inheritdoc cref="FileInfo.MoveTo(string,bool)"/>
29+
void MoveTo(string destFileName, bool overwrite);
30+
#endif
2731
/// <inheritdoc cref="FileInfo.Open(FileMode)"/>
2832
Stream Open(FileMode mode);
2933
/// <inheritdoc cref="FileInfo.Open(FileMode,FileAccess)"/>

tests/System.IO.Abstractions.TestingHelpers.Tests/MockFileInfoTests.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,27 @@ public void MockFileInfo_MoveTo_ThrowsExceptionIfSourceDoesntExist()
527527
Assert.Throws<FileNotFoundException>(action);
528528
}
529529

530+
531+
532+
#if FEATURE_FILE_MOVE_WITH_OVERWRITE
533+
[Test]
534+
public void MockFileInfo_MoveToWithOverwrite_ShouldSucceedWhenTargetAlreadyExists()
535+
{
536+
string sourceFilePath = XFS.Path(@"c:\something\demo.txt");
537+
string sourceFileContent = "this is some content";
538+
string destFilePath = XFS.Path(@"c:\somethingelse\demo1.txt");
539+
var fileSystem = new MockFileSystem(new Dictionary<string, MockFileData>
540+
{
541+
{sourceFilePath, new MockFileData(sourceFileContent)},
542+
{destFilePath, new MockFileData(sourceFileContent)}
543+
});
544+
545+
fileSystem.FileInfo.FromFileName(sourceFilePath).MoveTo(destFilePath, overwrite: true);
546+
547+
Assert.That(fileSystem.File.ReadAllText(destFilePath), Is.EqualTo(sourceFileContent));
548+
}
549+
#endif
550+
530551
[Test]
531552
public void MockFileInfo_CopyTo_ThrowsExceptionIfSourceDoesntExist()
532553
{

0 commit comments

Comments
 (0)