From ff73e44b081843ee0b45edbb4b98ac65226b7d1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Valentin=20Breu=C3=9F?= Date: Sun, 31 May 2026 15:52:31 +0200 Subject: [PATCH] test: kill notification/watcher triggering mutation survivors --- ...eSystem.DidNotTriggerNotification.Tests.cs | 19 +++++ .../FileSystem.TriggeredNotification.Tests.cs | 64 ++++++++++++++++ .../FileSystemWatcher.DidNotTrigger.Tests.cs | 22 ++++++ .../FileSystemWatcher.Triggered.Tests.cs | 73 +++++++++++++++++++ 4 files changed, 178 insertions(+) diff --git a/Tests/aweXpect.Testably.Tests/FileSystem.DidNotTriggerNotification.Tests.cs b/Tests/aweXpect.Testably.Tests/FileSystem.DidNotTriggerNotification.Tests.cs index 248e3f5..cea3405 100644 --- a/Tests/aweXpect.Testably.Tests/FileSystem.DidNotTriggerNotification.Tests.cs +++ b/Tests/aweXpect.Testably.Tests/FileSystem.DidNotTriggerNotification.Tests.cs @@ -142,6 +142,25 @@ await That(sut).DidNotTriggerNotification(c => c.Name == "other.txt") await That(Act).DoesNotThrow(); } + + [Fact] + public async Task WhenEventArrivesAsynchronouslyWithinTimeout_ShouldFail() + { + MockFileSystem sut = new(); + _ = Task.Run(async () => + { + await Task.Delay(20); + sut.File.WriteAllText("foo.txt", "x"); + }); + + async Task Act() + { + await That(sut).DidNotTriggerNotification().Within(TimeSpan.FromSeconds(30)); + } + + await That(Act).ThrowsException() + .WithMessage("*did not trigger a notification*but it was triggered*").AsWildcard(); + } } } } diff --git a/Tests/aweXpect.Testably.Tests/FileSystem.TriggeredNotification.Tests.cs b/Tests/aweXpect.Testably.Tests/FileSystem.TriggeredNotification.Tests.cs index 35c5b28..9cff464 100644 --- a/Tests/aweXpect.Testably.Tests/FileSystem.TriggeredNotification.Tests.cs +++ b/Tests/aweXpect.Testably.Tests/FileSystem.TriggeredNotification.Tests.cs @@ -321,6 +321,70 @@ async Task Act() await That(Act).DoesNotThrow(); } + + [Fact] + public async Task WithExactlyOnce_WhenTriggeredThreeTimes_ShouldFailWithCountInMessage() + { + MockFileSystem sut = new(); + using IAwaitableCallback reg = sut.Notify.OnEvent( + _ => { }, + c => c.ChangeType == WatcherChangeTypes.Created); + sut.File.WriteAllText("a.txt", "x"); + sut.File.WriteAllText("b.txt", "x"); + sut.File.WriteAllText("c.txt", "x"); + ChangeDescription[] created = reg.Wait(3, TimeSpan.FromSeconds(30)); + + async Task Act() + { + await That(sut).TriggeredNotification(c => c.ChangeType == WatcherChangeTypes.Created) + .Exactly(1.Times()) + .Within(TimeSpan.FromMilliseconds(100)); + } + + await That(Act).ThrowsException() + .WithMessage($$""" + Expected that sut + triggered a notification matching c => c.ChangeType == WatcherChangeTypes.Created exactly once within 0:00.100, + but it was triggered 3 times in [ + {{created[0]}}, + {{created[1]}}, + {{created[2]}} + ] + """); + } + + [Fact] + public async Task WithZeroTimeout_WhenNoPriorEvent_ShouldFailWithTimeoutMessage() + { + MockFileSystem sut = new(); + + async Task Act() + { + await That(sut).TriggeredNotification().Within(TimeSpan.Zero); + } + + await That(Act).ThrowsException() + .WithMessage(""" + Expected that sut + triggered a notification at least once within 0:00, + but it was not triggered + """); + } + + [Fact] + public async Task WithNegativeTimeout_ShouldThrowArgumentOutOfRangeException() + { + MockFileSystem sut = new(); + + async Task Act() + { + await That(sut).TriggeredNotification().Within(TimeSpan.FromMilliseconds(-1)); + } + + await That(Act).Throws() + .WithParamName("timeout").And + .WithMessage("The timeout must not be negative.*").AsWildcard(); + } } } } diff --git a/Tests/aweXpect.Testably.Tests/FileSystemWatcher.DidNotTrigger.Tests.cs b/Tests/aweXpect.Testably.Tests/FileSystemWatcher.DidNotTrigger.Tests.cs index 480fa1d..a86d85d 100644 --- a/Tests/aweXpect.Testably.Tests/FileSystemWatcher.DidNotTrigger.Tests.cs +++ b/Tests/aweXpect.Testably.Tests/FileSystemWatcher.DidNotTrigger.Tests.cs @@ -184,6 +184,28 @@ await That(sut).DidNotTrigger(c => c.Name == "other.txt") await That(Act).DoesNotThrow(); } + + [Fact] + public async Task WhenEventArrivesAsynchronouslyWithinTimeout_ShouldFail() + { + MockFileSystem fs = new(); + fs.InitializeIn("/x"); + using IFileSystemWatcher sut = fs.FileSystemWatcher.New("/x"); + sut.EnableRaisingEvents = true; + _ = Task.Run(async () => + { + await Task.Delay(20); + fs.File.WriteAllText("foo.txt", "x"); + }); + + async Task Act() + { + await That(sut).DidNotTrigger().Within(TimeSpan.FromSeconds(30)); + } + + await That(Act).ThrowsException() + .WithMessage("*did not trigger an event*but it was triggered*").AsWildcard(); + } } } } diff --git a/Tests/aweXpect.Testably.Tests/FileSystemWatcher.Triggered.Tests.cs b/Tests/aweXpect.Testably.Tests/FileSystemWatcher.Triggered.Tests.cs index 6b9ad00..37cd5a3 100644 --- a/Tests/aweXpect.Testably.Tests/FileSystemWatcher.Triggered.Tests.cs +++ b/Tests/aweXpect.Testably.Tests/FileSystemWatcher.Triggered.Tests.cs @@ -407,6 +407,79 @@ async Task Act() await That(Act).DoesNotThrow(); } + + [Fact] + public async Task WithExactlyOnce_WhenTriggeredThreeTimes_ShouldFailWithCountInMessage() + { + MockFileSystem fs = new(); + fs.InitializeIn("/x"); + using IFileSystemWatcher sut = fs.FileSystemWatcher.New("/x"); + sut.EnableRaisingEvents = true; + using IAwaitableCallback reg = fs.Watcher.OnTriggered( + _ => { }, + c => c.FileSystemWatcher == sut && c.ChangeType == WatcherChangeTypes.Created); + fs.File.WriteAllText("a.txt", "x"); + fs.File.WriteAllText("b.txt", "x"); + fs.File.WriteAllText("c.txt", "x"); + WatcherChangeDescription[] created = reg.Wait(3, TimeSpan.FromSeconds(30)); + + async Task Act() + { + await That(sut).Triggered(c => c.ChangeType == WatcherChangeTypes.Created) + .Exactly(1.Times()) + .Within(TimeSpan.FromMilliseconds(100)); + } + + await That(Act).ThrowsException() + .WithMessage($$""" + Expected that sut + triggered an event matching c => c.ChangeType == WatcherChangeTypes.Created exactly once within 0:00.100, + but it was triggered 3 times in [ + {{created[0]}}, + {{created[1]}}, + {{created[2]}} + ] + """); + } + + [Fact] + public async Task WithZeroTimeout_WhenNoEvent_ShouldFailWithTimeoutMessage() + { + MockFileSystem fs = new(); + fs.InitializeIn("/x"); + using IFileSystemWatcher sut = fs.FileSystemWatcher.New("/x"); + sut.EnableRaisingEvents = true; + + async Task Act() + { + await That(sut).Triggered().Within(TimeSpan.Zero); + } + + await That(Act).ThrowsException() + .WithMessage(""" + Expected that sut + triggered an event at least once within 0:00, + but it was not triggered + """); + } + + [Fact] + public async Task WithNegativeTimeout_ShouldThrowArgumentOutOfRangeException() + { + MockFileSystem fs = new(); + fs.InitializeIn("/x"); + using IFileSystemWatcher sut = fs.FileSystemWatcher.New("/x"); + sut.EnableRaisingEvents = true; + + async Task Act() + { + await That(sut).Triggered().Within(TimeSpan.FromMilliseconds(-1)); + } + + await That(Act).Throws() + .WithParamName("timeout").And + .WithMessage("The timeout must not be negative.*").AsWildcard(); + } } } }