Skip to main content

Intercept & notify

MockFileSystem exposes three hooks for reacting to file system activity in tests:

  • Intercept runs before an operation completes and can throw to abort it.
  • Notify runs after an operation completes and supports awaiting the next event.
  • Watcher runs after the IFileSystemWatcher raised an event - see FileSystemWatcher.

All three return an IAwaitableCallback<ChangeDescription> with the same shape:

  • Dispose() removes the subscription.
  • Wait(int count = 1, TimeSpan? timeout = null) blocks until count events arrived; defaults to a 30-second timeout.
  • WaitAsync(...) is the async counterpart and additionally accepts a CancellationToken.

This page describes that count/timeout shape once and just shows the registration calls below.

Intercept - abort an operation

MockFileSystem fileSystem = new();

fileSystem.Intercept.Creating(FileSystemTypes.File,
_ => throw new IOException("disk full"));

// Throws "disk full"
fileSystem.File.WriteAllText("a.txt", "x");

Useful for simulating disk errors, permission failures or race conditions.

IInterceptionHandler exposes Changing, Creating and Deleting extensions. Each takes a FileSystemTypes (File, Directory or DirectoryOrFile), an optional globPattern (defaults to "*") and an optional predicate for finer filtering.

Notify - await an event

MockFileSystem fileSystem = new();

using var notify = fileSystem.Notify
.OnCreated(FileSystemTypes.File);

fileSystem.File.Create("some-file.txt");

ChangeDescription[] events = notify.Wait(count: 1);
// events[0].Path == "some-file.txt"

The recommended pattern is: register the callback, do the work, then call Wait (or WaitAsync for an async test).

OnChanged, OnCreated and OnDeleted are all available, with the same globPattern / predicate filters as Intercept.

Streaming events

On .NET 6+ you can stream the same callback as an async sequence:

await foreach (ChangeDescription change in
fileSystem.Notify.OnCreated(FileSystemTypes.File).ToAsyncEnumerable())
{
// process every file creation as it happens
}

A 30-second default timeout prevents the loop from hanging forever when no events arrive; pass an explicit timeout (TimeSpan? or int milliseconds) or a CancellationToken to override it.