Skip to content

Commit c778e34

Browse files
authored
fix: correctly handle readonly directories during delete (#854)
This PR fixes handling of readonly directories during delete operations to properly match Windows behavior. The fix ensures that attempting to delete a readonly directory on Windows throws an IOException with the correct error message and path information. ### Key changes: - Add test coverage for readonly directory deletion behavior - Fix the exception thrown when accessing readonly directories to include the full path
1 parent 1a40ae3 commit c778e34

File tree

4 files changed

+46
-1
lines changed

4 files changed

+46
-1
lines changed

Source/Testably.Abstractions.Testing/Storage/InMemoryContainer.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,9 @@ public IStorageAccessHandle RequestAccess(FileAccess access, FileShare share,
190190
!ignoreMetadataErrors &&
191191
Attributes.HasFlag(FileAttributes.ReadOnly))
192192
{
193-
throw ExceptionFactory.AccessToPathDenied();
193+
throw ExceptionFactory.AccessToPathDenied(_fileSystem.Execute.IsNetFramework
194+
? _location.FriendlyName
195+
: _location.FullPath);
194196
}
195197
#if FEATURE_FILESYSTEM_UNIXFILEMODE
196198
if (!deleteAccess && !_fileSystem.UnixFileModeStrategy

Source/Testably.Abstractions.Testing/Storage/InMemoryStorage.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ public bool DeleteContainer(
170170
location);
171171

172172
using (container.RequestAccess(FileAccess.Write, FileShare.ReadWrite,
173+
ignoreMetadataErrors: false,
173174
deleteAccess: true))
174175
{
175176
if (_containers.TryRemove(location, out IStorageContainer? removed))

Tests/Testably.Abstractions.Tests/FileSystem/Directory/DeleteTests.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,27 @@ await That(Act).Throws<DirectoryNotFoundException>()
6262
.WithHResult(-2147024893);
6363
}
6464

65+
[Theory]
66+
[AutoData]
67+
public async Task Delete_ReadonlyDirectory_ShouldThrowIOExceptionOnWindows(string path)
68+
{
69+
IDirectoryInfo sut = FileSystem.Directory.CreateDirectory(path);
70+
sut.Attributes = FileAttributes.ReadOnly;
71+
sut.Refresh();
72+
73+
void Act()
74+
{
75+
FileSystem.Directory.Delete(path);
76+
}
77+
78+
await That(Act).Throws<IOException>()
79+
.OnlyIf(Test.RunsOnWindows)
80+
.WithMessage(Test.IsNetFramework
81+
? $"Access to the path '{path}' is denied."
82+
: $"Access to the path '{sut.FullName}' is denied.").And
83+
.WithHResult(-2146232800);
84+
}
85+
6586
[Theory]
6687
[AutoData]
6788
public async Task Delete_Recursive_MissingDirectory_ShouldThrowDirectoryNotFoundException(

Tests/Testably.Abstractions.Tests/FileSystem/DirectoryInfo/DeleteTests.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,27 @@ await That(Act).Throws<DirectoryNotFoundException>()
2222
.WithHResult(-2147024893);
2323
}
2424

25+
[Theory]
26+
[AutoData]
27+
public async Task Delete_ReadonlyDirectory_ShouldThrowIOExceptionOnWindows(string path)
28+
{
29+
IDirectoryInfo sut = FileSystem.Directory.CreateDirectory(path);
30+
sut.Attributes = FileAttributes.ReadOnly;
31+
sut.Refresh();
32+
33+
void Act()
34+
{
35+
sut.Delete();
36+
}
37+
38+
await That(Act).Throws<IOException>()
39+
.OnlyIf(Test.RunsOnWindows)
40+
.WithMessage(Test.IsNetFramework
41+
? $"Access to the path '{path}' is denied."
42+
: $"Access to the path '{sut.FullName}' is denied.").And
43+
.WithHResult(-2146232800);
44+
}
45+
2546
[Theory]
2647
[AutoData]
2748
public async Task Delete_Recursive_WithOpenFile_ShouldThrowIOException_OnWindows(

0 commit comments

Comments
 (0)