Unix file mode
To simulate POSIX permissions in the mock, plug in an IUnixFileModeStrategy via WithUnixFileModeStrategy(...). Without one, the mock grants access to every entry whose UnixFileMode is not None.
The strategy decides:
- whether a given user/group is allowed to read or write a path (
IsAccessGranted) - what to record when the file mode is set, for example by
File.SetUnixFileMode(...)(OnSetUnixFileMode)
A typical implementation stores the file's user and group alongside the file via IFileSystemExtensibility, then uses that data plus the file's UnixFileMode to decide whether to grant access. When access is denied, the mock throws UnauthorizedAccessException.
WithUnixFileModeStrategy throws PlatformNotSupportedException when the host (or simulated OS) is Windows. On a Windows machine, simulate Linux or macOS.
Example: simulating users and groups
The strategy below is not part of the library; copy and adapt it. It lets a test simulate "running as user X in group Y" via fluent setters and records the simulated user and group as the owner whenever the mode of an entry is set. It grants read access when:
- the mode includes
OtherRead, or - the mode includes
GroupReadand the owner's group matches the simulated group, or - the mode includes
UserReadand the owner matches the simulated user
The same rules apply to write access with the *Write flags.
SimulatedUserStrategy
public class SimulatedUserStrategy : IUnixFileModeStrategy
{
private string _user = "";
private string _group = "";
public SimulatedUserStrategy SimulateUser(string user) { _user = user; return this; }
public SimulatedUserStrategy SimulateGroup(string group) { _group = group; return this; }
public void OnSetUnixFileMode(string fullPath,
IFileSystemExtensibility extensibility, UnixFileMode mode)
{
// Record the simulated owner at the moment the file's mode was set
extensibility.StoreMetadata(nameof(SimulatedUserStrategy),
new UserGroup(_user, _group));
}
public bool IsAccessGranted(string fullPath,
IFileSystemExtensibility extensibility,
UnixFileMode mode, FileAccess requestedAccess)
{
UserGroup owner = extensibility
.RetrieveMetadata<UserGroup>(nameof(SimulatedUserStrategy))
?? new UserGroup(_user, _group);
bool readOk =
mode.HasFlag(UnixFileMode.OtherRead) ||
(mode.HasFlag(UnixFileMode.GroupRead) && owner.Group == _group) ||
(mode.HasFlag(UnixFileMode.UserRead) && owner.User == _user);
bool writeOk =
mode.HasFlag(UnixFileMode.OtherWrite) ||
(mode.HasFlag(UnixFileMode.GroupWrite) && owner.Group == _group) ||
(mode.HasFlag(UnixFileMode.UserWrite) && owner.User == _user);
return requestedAccess switch
{
FileAccess.Read => readOk,
FileAccess.Write => writeOk,
_ => readOk && writeOk,
};
}
private record UserGroup(string User, string Group);
}
Wiring it into a test
SimulatedUserStrategy strategy = new();
MockFileSystem fileSystem = new MockFileSystem(o => o
.SimulatingOperatingSystem(SimulationMode.Linux))
.WithUnixFileModeStrategy(strategy);
// "alice" creates a directory readable only by the group "curators"
strategy.SimulateUser("alice").SimulateGroup("curators");
fileSystem.Directory.CreateDirectory("restoration", UnixFileMode.GroupRead);
// "bob" (also a curator) can read it
strategy.SimulateUser("bob").SimulateGroup("curators");
fileSystem.Directory.GetFiles("restoration"); // no exception
// switch to a different group → read denied
strategy.SimulateGroup("visitors");
fileSystem.Directory.GetFiles("restoration"); // throws UnauthorizedAccessException
Asserting denial
strategy.SimulateUser("alice");
fileSystem.Directory.CreateDirectory("vault", UnixFileMode.UserWrite);
strategy.SimulateUser("bob");
Action act = () => fileSystem.Directory.CreateDirectory("vault/drafts");
await That(act).Throws<UnauthorizedAccessException>();