Skip to content

Commit

Permalink
refactor: extract ACL related functionality (#913)
Browse files Browse the repository at this point in the history
Remove the ACL-Features from the interfaces and instead implement them as extension methods implemented in "TestableIO.System.IO.Abstractions.Wrappers".

This removes the dependency on `System.IO.FileSystem.AccessControl` from the interface project.

This is part of the approach discussed in #883

BREAKING CHANGE: This refactoring removes ACL-related methods from the interface project and replaces them with extension methods in `TestableIO.System.IO.Abstractions.Wrappers`.
  • Loading branch information
vbreuss committed Dec 8, 2022
1 parent b662500 commit 24d1d07
Show file tree
Hide file tree
Showing 44 changed files with 628 additions and 499 deletions.
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Runtime.Versioning;
using System.Security.AccessControl;
using System.Text.RegularExpressions;

namespace System.IO.Abstractions.TestingHelpers
Expand Down Expand Up @@ -39,17 +36,10 @@ public class MockDirectory : DirectoryBase
/// <inheritdoc />
public override IDirectoryInfo CreateDirectory(string path)
{
return CreateDirectoryInternal(path, null);
return CreateDirectoryInternal(path);
}


/// <inheritdoc />
public override IDirectoryInfo CreateDirectory(string path, DirectorySecurity directorySecurity)
{
return CreateDirectoryInternal(path, directorySecurity);
}

private IDirectoryInfo CreateDirectoryInternal(string path, DirectorySecurity directorySecurity)
private IDirectoryInfo CreateDirectoryInternal(string path)
{
if (path == null)
{
Expand Down Expand Up @@ -80,11 +70,6 @@ private IDirectoryInfo CreateDirectoryInternal(string path, DirectorySecurity di

var created = new MockDirectoryInfo(mockFileDataAccessor, path);

if (directorySecurity != null)
{
created.SetAccessControl(directorySecurity);
}

return created;
}

Expand Down Expand Up @@ -173,31 +158,6 @@ public override bool Exists(string path)
}


/// <inheritdoc />
[SupportedOSPlatform("windows")]
public override DirectorySecurity GetAccessControl(string path)
{
mockFileDataAccessor.PathVerifier.IsLegalAbsoluteOrRelative(path, "path");
path = path.TrimSlashes();

if (!mockFileDataAccessor.Directory.Exists(path))
{
throw CommonExceptions.CouldNotFindPartOfPath(path);
}

var directoryData = (MockDirectoryData)mockFileDataAccessor.GetFile(path);
return directoryData.AccessControl;
}


/// <inheritdoc />
[SupportedOSPlatform("windows")]
public override DirectorySecurity GetAccessControl(string path, AccessControlSections includeSections)
{
return GetAccessControl(path);
}


/// <inheritdoc />
public override DateTime GetCreationTime(string path)
{
Expand Down Expand Up @@ -559,22 +519,6 @@ public override IFileSystemInfo ResolveLinkTarget(string linkPath, bool returnFi

#endif

/// <inheritdoc />
[SupportedOSPlatform("windows")]
public override void SetAccessControl(string path, DirectorySecurity directorySecurity)
{
mockFileDataAccessor.PathVerifier.IsLegalAbsoluteOrRelative(path, "path");
path = path.TrimSlashes();

if (!mockFileDataAccessor.Directory.Exists(path))
{
throw CommonExceptions.CouldNotFindPartOfPath(path);
}

var directoryData = (MockDirectoryData)mockFileDataAccessor.GetFile(path);
directoryData.AccessControl = directorySecurity;
}

/// <inheritdoc />
public override void SetCreationTime(string path, DateTime creationTime)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Versioning;
using System.Security.AccessControl;

namespace System.IO.Abstractions.TestingHelpers
Expand All @@ -8,7 +9,7 @@ namespace System.IO.Abstractions.TestingHelpers

/// <inheritdoc />
[Serializable]
public class MockDirectoryInfo : DirectoryInfoBase
public class MockDirectoryInfo : DirectoryInfoBase, IFileSystemAclSupport
{
private readonly IMockFileDataAccessor mockFileDataAccessor;
private readonly string directoryPath;
Expand All @@ -26,6 +27,15 @@ public MockDirectoryInfo(IMockFileDataAccessor mockFileDataAccessor, string dire
{
this.mockFileDataAccessor = mockFileDataAccessor ?? throw new ArgumentNullException(nameof(mockFileDataAccessor));

if (directoryPath == null)
{
throw new ArgumentNullException("path", StringResources.Manager.GetString("VALUE_CANNOT_BE_NULL"));
}
if (directoryPath.Trim() == string.Empty)
{
throw CommonExceptions.PathIsNotOfALegalForm("path");
}

originalPath = directoryPath;
directoryPath = mockFileDataAccessor.Path.GetFullPath(directoryPath);

Expand Down Expand Up @@ -179,14 +189,7 @@ public override void Create()
mockFileDataAccessor.Directory.CreateDirectory(FullName);
refreshOnNextRead = true;
}

/// <inheritdoc />
public override void Create(DirectorySecurity directorySecurity)
{
mockFileDataAccessor.Directory.CreateDirectory(FullName, directorySecurity);
refreshOnNextRead = true;
}


/// <inheritdoc />
public override IDirectoryInfo CreateSubdirectory(string path)
{
Expand Down Expand Up @@ -277,19 +280,7 @@ public override IEnumerable<IFileSystemInfo> EnumerateFileSystemInfos(string sea
return GetFileSystemInfos(searchPattern, enumerationOptions);
}
#endif

/// <inheritdoc />
public override DirectorySecurity GetAccessControl()
{
return mockFileDataAccessor.Directory.GetAccessControl(directoryPath);
}

/// <inheritdoc />
public override DirectorySecurity GetAccessControl(AccessControlSections includeSections)
{
return mockFileDataAccessor.Directory.GetAccessControl(directoryPath, includeSections);
}


/// <inheritdoc />
public override IDirectoryInfo[] GetDirectories()
{
Expand Down Expand Up @@ -388,13 +379,7 @@ public override void MoveTo(string destDirName)
{
mockFileDataAccessor.Directory.Move(directoryPath, destDirName);
}

/// <inheritdoc />
public override void SetAccessControl(DirectorySecurity directorySecurity)
{
mockFileDataAccessor.Directory.SetAccessControl(directoryPath, directorySecurity);
}


/// <inheritdoc />
public override IDirectoryInfo Parent
{
Expand Down Expand Up @@ -435,5 +420,32 @@ public override string ToString()
{
return originalPath;
}

/// <inheritdoc cref="IFileSystemAclSupport.GetAccessControl()" />
[SupportedOSPlatform("windows")]
public object GetAccessControl()
{
return GetMockDirectoryData().AccessControl;
}

/// <inheritdoc cref="IFileSystemAclSupport.GetAccessControl(IFileSystemAclSupport.AccessControlSections)" />
[SupportedOSPlatform("windows")]
public object GetAccessControl(IFileSystemAclSupport.AccessControlSections includeSections)
{
return GetMockDirectoryData().AccessControl;
}

/// <inheritdoc cref="IFileSystemAclSupport.SetAccessControl(object)" />
[SupportedOSPlatform("windows")]
public void SetAccessControl(object value)
{
GetMockDirectoryData().AccessControl = value as DirectorySecurity;
}

private MockDirectoryData GetMockDirectoryData()
{
return mockFileDataAccessor.GetFile(directoryPath) as MockDirectoryData
?? throw CommonExceptions.CouldNotFindPartOfPath(directoryPath);
}
}
}
40 changes: 0 additions & 40 deletions src/TestableIO.System.IO.Abstractions.TestingHelpers/MockFile.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Runtime.Versioning;
using System.Security.AccessControl;
using System.Text;

namespace System.IO.Abstractions.TestingHelpers
Expand Down Expand Up @@ -268,28 +266,6 @@ public override bool Exists(string path)
return false;
}

/// <inheritdoc />
[SupportedOSPlatform("windows")]
public override FileSecurity GetAccessControl(string path)
{
mockFileDataAccessor.PathVerifier.IsLegalAbsoluteOrRelative(path, "path");

if (!mockFileDataAccessor.FileExists(path))
{
throw CommonExceptions.FileNotFound(path);
}

var fileData = mockFileDataAccessor.GetFile(path);
return fileData.AccessControl;
}

/// <inheritdoc />
[SupportedOSPlatform("windows")]
public override FileSecurity GetAccessControl(string path, AccessControlSections includeSections)
{
return GetAccessControl(path);
}

/// <summary>
/// Gets the <see cref="FileAttributes"/> of the file on the path.
/// </summary>
Expand Down Expand Up @@ -732,22 +708,6 @@ public override IFileSystemInfo ResolveLinkTarget(string linkPath, bool returnFi
}
#endif

/// <inheritdoc />
[SupportedOSPlatform("windows")]
public override void SetAccessControl(string path, FileSecurity fileSecurity)
{
mockFileDataAccessor.PathVerifier.IsLegalAbsoluteOrRelative(path, "path");

if (!mockFileDataAccessor.FileExists(path))
{
throw CommonExceptions.FileNotFound(path);
}

var fileData = mockFileDataAccessor.GetFile(path);
mockFileDataAccessor.AdjustTimes(fileData, TimeAdjustments.LastAccessTime);
fileData.AccessControl = fileSecurity;
}

/// <inheritdoc />
public override void SetAttributes(string path, FileAttributes fileAttributes)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ public string TextContents
public DateTimeOffset CreationTime
{
get { return creationTime; }
set{ creationTime = value.ToUniversalTime(); }
set { creationTime = value.ToUniversalTime(); }
}
private DateTimeOffset creationTime;

Expand Down Expand Up @@ -179,7 +179,7 @@ public DateTimeOffset LastWriteTime
public FileAttributes Attributes { get; set; } = FileAttributes.Normal;

/// <summary>
/// Gets or sets <see cref="FileSecurity"/> of the <see cref="MockFileData"/>. This is the object that is returned for this <see cref="MockFileData"/> when calling <see cref="FileBase.GetAccessControl(string)"/>.
/// Gets or sets <see cref="FileSecurity"/> of the <see cref="MockFileData"/>.
/// </summary>
[SupportedOSPlatform("windows")]
public FileSecurity AccessControl
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace System.IO.Abstractions.TestingHelpers
{
/// <inheritdoc />
[Serializable]
public class MockFileInfo : FileInfoBase
public class MockFileInfo : FileInfoBase, IFileSystemAclSupport
{
private readonly IMockFileDataAccessor mockFileSystem;
private string path;
Expand All @@ -18,7 +18,8 @@ public class MockFileInfo : FileInfoBase
public MockFileInfo(IMockFileDataAccessor mockFileSystem, string path) : base(mockFileSystem?.FileSystem)
{
this.mockFileSystem = mockFileSystem ?? throw new ArgumentNullException(nameof(mockFileSystem));
this.originalPath = path ?? throw new ArgumentNullException(nameof(path));
mockFileSystem.PathVerifier.IsLegalAbsoluteOrRelative(path, "path");
this.originalPath = path;
this.path = mockFileSystem.Path.GetFullPath(path);
this.mockFile = new MockFile(mockFileSystem);
Refresh();
Expand Down Expand Up @@ -256,21 +257,7 @@ public override void Encrypt()
var mockFileData = GetMockFileDataForWrite();
mockFileData.Attributes |= FileAttributes.Encrypted;
}

/// <inheritdoc />
[SupportedOSPlatform("windows")]
public override FileSecurity GetAccessControl()
{
return mockFileSystem.File.GetAccessControl(this.path);
}

/// <inheritdoc />
[SupportedOSPlatform("windows")]
public override FileSecurity GetAccessControl(AccessControlSections includeSections)
{
return mockFileSystem.File.GetAccessControl(this.path, includeSections);
}


/// <inheritdoc />
public override void MoveTo(string destFileName)
{
Expand Down Expand Up @@ -334,14 +321,7 @@ public override IFileInfo Replace(string destinationFileName, string destination
mockFile.Replace(path, destinationFileName, destinationBackupFileName, ignoreMetadataErrors);
return mockFileSystem.FileInfo.New(destinationFileName);
}

/// <inheritdoc />
[SupportedOSPlatform("windows")]
public override void SetAccessControl(FileSecurity fileSecurity)
{
mockFile.SetAccessControl(this.path, fileSecurity);
}


/// <inheritdoc />
public override IDirectoryInfo Directory
{
Expand Down Expand Up @@ -404,6 +384,33 @@ public override string ToString()
return originalPath;
}

/// <inheritdoc cref="IFileSystemAclSupport.GetAccessControl()" />
[SupportedOSPlatform("windows")]
public object GetAccessControl()
{
return GetMockFileData().AccessControl;
}

/// <inheritdoc cref="IFileSystemAclSupport.GetAccessControl(IFileSystemAclSupport.AccessControlSections)" />
[SupportedOSPlatform("windows")]
public object GetAccessControl(IFileSystemAclSupport.AccessControlSections includeSections)
{
return GetMockFileData().AccessControl;
}

/// <inheritdoc cref="IFileSystemAclSupport.SetAccessControl(object)" />
[SupportedOSPlatform("windows")]
public void SetAccessControl(object value)
{
GetMockFileData().AccessControl = value as FileSecurity;
}

private MockFileData GetMockFileData()
{
return mockFileSystem.GetFile(path)
?? throw CommonExceptions.FileNotFound(path);
}

private static DateTime AdjustUnspecifiedKind(DateTime time, DateTimeKind fallbackKind)
{
if (time.Kind == DateTimeKind.Unspecified)
Expand Down
Loading

0 comments on commit 24d1d07

Please sign in to comment.