From bc47b5c492101604f91a5eec9ff8e924870be1cb Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Sun, 1 Nov 2026 14:36:56 +0100 Subject: [PATCH] Upgraded the tests to NUnit v5.0.0 and awaited their asynchronous assertions --- .../DataSourceERICancellationTests.cs | 4 ++-- app/Tests/Tests.csproj | 21 ++++++++----------- .../Tools/Databases/MailboxIndexStoreTests.cs | 12 +++++------ .../Tools/Databases/MailboxStateStoreTests.cs | 4 ++-- app/Tests/Tools/FileExportFeedbackTests.cs | 4 ++-- app/Tests/Tools/FileTypesTests.cs | 2 +- .../Tools/Mail/ImapMailboxConnectorTests.cs | 4 ++-- .../Tools/Mail/MailAttachmentPiecesTests.cs | 12 +++++------ .../Media/TranscriptPromptInjectionTests.cs | 4 ++-- app/Tests/Tools/PassageProvenanceTests.cs | 4 ++-- app/Tests/Tools/RetrievalPagingTests.cs | 4 ++-- .../Tools/ToolCalling/CountMailsToolTests.cs | 2 +- .../ToolCalling/MailToolArgumentsTests.cs | 2 +- .../Tools/ToolCalling/ReadMailToolTests.cs | 2 +- .../ReadWebPageAllowedPrivateHostTests.cs | 8 +++---- .../ReadWebPageFreeAddressChoiceTests.cs | 4 ++-- ...ReadWebPageOutboundDataRestrictionTests.cs | 4 ++-- .../Tools/ToolCalling/SearchMailsToolTests.cs | 2 +- .../SemanticSearchToolRequestTests.cs | 2 +- .../ToolCalling/ToolArgumentReaderTests.cs | 2 +- .../ToolCalling/WebSearchToolArgumentTests.cs | 2 +- 21 files changed, 51 insertions(+), 54 deletions(-) diff --git a/app/Tests/Settings/DataSourceERICancellationTests.cs b/app/Tests/Settings/DataSourceERICancellationTests.cs index 1498bf5d5..b0df86eb5 100644 --- a/app/Tests/Settings/DataSourceERICancellationTests.cs +++ b/app/Tests/Settings/DataSourceERICancellationTests.cs @@ -65,12 +65,12 @@ public sealed class DataSourceERICancellationTests } [Test] - public void ACancelledSearchStops() + public async Task ACancelledSearchStops() { using var cancellation = new CancellationTokenSource(); cancellation.Cancel(); - Assert.CatchAsync(async () => await UNREACHABLE.RetrieveDataAsync("query", 1, new ChatThread(), cancellation.Token), "Reporting the data source as not searched would carry on after the user cancelled."); + await Assert.CatchAsync(async () => await UNREACHABLE.RetrieveDataAsync("query", 1, new ChatThread(), cancellation.Token), "Reporting the data source as not searched would carry on after the user cancelled."); } [Test] diff --git a/app/Tests/Tests.csproj b/app/Tests/Tests.csproj index 8b115bef6..5277865b1 100644 --- a/app/Tests/Tests.csproj +++ b/app/Tests/Tests.csproj @@ -10,29 +10,26 @@ - + - + - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/app/Tests/Tools/Databases/MailboxIndexStoreTests.cs b/app/Tests/Tools/Databases/MailboxIndexStoreTests.cs index 7a910b427..406b33e07 100644 --- a/app/Tests/Tools/Databases/MailboxIndexStoreTests.cs +++ b/app/Tests/Tools/Databases/MailboxIndexStoreTests.cs @@ -233,13 +233,13 @@ public sealed class MailboxIndexStoreTests { var mailId = await this.StoreDocumentAsync(KEY_A); - Assert.Multiple(() => + using (Assert.EnterMultipleScope()) { - Assert.ThrowsAsync(() => this.Client.UpsertMailAsync(DATA_SOURCE_ID, Mail(mailId), TOKEN), "A mail which lies nowhere would be an orphan from the start."); - Assert.ThrowsAsync(() => this.Client.UpsertMailAsync(DATA_SOURCE_ID, Mail(mailId, At(INBOX, 7), At(INBOX, 7)), TOKEN)); - Assert.ThrowsAsync(() => this.Client.UpsertMailAsync(DATA_SOURCE_ID, Mail(mailId, At("Unknown", 1)), TOKEN)); - Assert.ThrowsAsync(() => this.Client.UpsertMailAsync(DATA_SOURCE_ID, Mail(mailId, At(INBOX, 7)) with { ReferenceMessageIds = ["one two@example.org"] }, TOKEN), "Stored separated by spaces, this one would come back as two."); - }); + await Assert.ThrowsAsync(() => this.Client.UpsertMailAsync(DATA_SOURCE_ID, Mail(mailId), TOKEN), "A mail which lies nowhere would be an orphan from the start."); + await Assert.ThrowsAsync(() => this.Client.UpsertMailAsync(DATA_SOURCE_ID, Mail(mailId, At(INBOX, 7), At(INBOX, 7)), TOKEN)); + await Assert.ThrowsAsync(() => this.Client.UpsertMailAsync(DATA_SOURCE_ID, Mail(mailId, At("Unknown", 1)), TOKEN)); + await Assert.ThrowsAsync(() => this.Client.UpsertMailAsync(DATA_SOURCE_ID, Mail(mailId, At(INBOX, 7)) with { ReferenceMessageIds = ["one two@example.org"] }, TOKEN), "Stored separated by spaces, this one would come back as two."); + } } /// diff --git a/app/Tests/Tools/Databases/MailboxStateStoreTests.cs b/app/Tests/Tools/Databases/MailboxStateStoreTests.cs index 18b6f22f1..1fced39ee 100644 --- a/app/Tests/Tools/Databases/MailboxStateStoreTests.cs +++ b/app/Tests/Tools/Databases/MailboxStateStoreTests.cs @@ -91,9 +91,9 @@ public sealed class MailboxStateStoreTests } [Test] - public void ARemovalOfNoMailIsNothingToHoldBack() + public async Task ARemovalOfNoMailIsNothingToHoldBack() { - Assert.ThrowsAsync(() => this.Client.HoldBackMailRemovalAsync(DATA_SOURCE_ID, 0, TOKEN)); + await Assert.ThrowsAsync(() => this.Client.HoldBackMailRemovalAsync(DATA_SOURCE_ID, 0, TOKEN)); } [Test] diff --git a/app/Tests/Tools/FileExportFeedbackTests.cs b/app/Tests/Tools/FileExportFeedbackTests.cs index b17501f6d..06cff1176 100644 --- a/app/Tests/Tools/FileExportFeedbackTests.cs +++ b/app/Tests/Tools/FileExportFeedbackTests.cs @@ -65,10 +65,10 @@ public sealed class FileExportFeedbackTests } [Test] - public void AnExceptionRemovesTheRunningNotification() + public async Task AnExceptionRemovesTheRunningNotification() { var sent = new SentNotifications(); - Assert.ThrowsAsync(async () => + await Assert.ThrowsAsync(async () => { await using var feedback = new FileExportFeedback(sent.Send, _ => Task.CompletedTask); feedback.ShowRunning(FILE_PATH); diff --git a/app/Tests/Tools/FileTypesTests.cs b/app/Tests/Tools/FileTypesTests.cs index 81310044c..104d3e149 100644 --- a/app/Tests/Tools/FileTypesTests.cs +++ b/app/Tests/Tools/FileTypesTests.cs @@ -59,7 +59,7 @@ public class FileTypesTests .ToArray(); Assert.That(extensions, Is.Not.Empty); - Assert.That(extensions, Has.All.Matches(extension => extension == extension.ToLowerInvariant() && !extension.Contains('.'))); + Assert.That(extensions, Has.All.Matches(extension => extension is not null && extension == extension.ToLowerInvariant() && !extension.Contains('.'))); } [Test] diff --git a/app/Tests/Tools/Mail/ImapMailboxConnectorTests.cs b/app/Tests/Tools/Mail/ImapMailboxConnectorTests.cs index 142cbc136..d177b545b 100644 --- a/app/Tests/Tools/Mail/ImapMailboxConnectorTests.cs +++ b/app/Tests/Tools/Mail/ImapMailboxConnectorTests.cs @@ -90,7 +90,7 @@ public sealed class ImapMailboxConnectorTests // failure instead of this one. // await using var connector = new ImapMailboxConnector(); - var exception = Assert.ThrowsAsync(() => connector.ConnectAsync(mailbox, password, MailServerPolicy.ANY_SERVER, CancellationToken.None)); + var exception = await Assert.ThrowsAsync(() => connector.ConnectAsync(mailbox, password, MailServerPolicy.ANY_SERVER, CancellationToken.None)); Assert.That(exception?.Failure, Is.EqualTo(MailboxConnectionFailure.INVALID_SETTINGS)); } @@ -103,7 +103,7 @@ public sealed class ImapMailboxConnectorTests // await using var connector = new ImapMailboxConnector(); var policy = new MailServerPolicy(true, ["imap.intra.example.org"]); - var exception = Assert.ThrowsAsync(() => connector.ConnectAsync(MAILBOX, PASSWORD, policy, CancellationToken.None)); + var exception = await Assert.ThrowsAsync(() => connector.ConnectAsync(MAILBOX, PASSWORD, policy, CancellationToken.None)); Assert.That(exception?.Failure, Is.EqualTo(MailboxConnectionFailure.SERVER_NOT_ALLOWED)); } diff --git a/app/Tests/Tools/Mail/MailAttachmentPiecesTests.cs b/app/Tests/Tools/Mail/MailAttachmentPiecesTests.cs index e35a171b9..241545c3f 100644 --- a/app/Tests/Tools/Mail/MailAttachmentPiecesTests.cs +++ b/app/Tests/Tools/Mail/MailAttachmentPiecesTests.cs @@ -61,22 +61,22 @@ public sealed class MailAttachmentPiecesTests } [Test] - public void AnUnknownEncodingFetchesNothing() + public async Task AnUnknownEncodingFetchesNothing() { var server = new PieceServer(Encoding.ASCII.GetBytes("Uryyb")); - Assert.Multiple(() => + using (Assert.EnterMultipleScope()) { - Assert.ThrowsAsync(async () => await WriteDecodedAsync(server, "x-rot13")); + await Assert.ThrowsAsync(async () => await WriteDecodedAsync(server, "x-rot13")); Assert.That(server.RequestedOffsets, Is.Empty); - }); + } } [Test] - public void APieceLargerThanAskedForIsRefused() + public async Task APieceLargerThanAskedForIsRefused() { // Taken as it came, the next piece would repeat what this one already delivered: var server = new PieceServer(new byte[100], deliveredBytes: PIECE_BYTES + 1); - Assert.ThrowsAsync(async () => await WriteDecodedAsync(server, "binary")); + await Assert.ThrowsAsync(async () => await WriteDecodedAsync(server, "binary")); } private static async Task WriteDecodedAsync(PieceServer server, string? transferEncoding) diff --git a/app/Tests/Tools/Media/TranscriptPromptInjectionTests.cs b/app/Tests/Tools/Media/TranscriptPromptInjectionTests.cs index b86b4c943..5e00b18bc 100644 --- a/app/Tests/Tools/Media/TranscriptPromptInjectionTests.cs +++ b/app/Tests/Tools/Media/TranscriptPromptInjectionTests.cs @@ -97,11 +97,11 @@ public sealed class TranscriptPromptInjectionTests } [Test] - public void OnlyAReadyTranscriptCanBeRead() + public async Task OnlyAReadyTranscriptCanBeRead() { var transcript = PersistentMediaTranscriptResult.Unavailable(PersistentMediaTranscriptStatus.NO_PROVIDER, null, "No provider."); - Assert.ThrowsAsync(() => PersistentMediaTranscript.ReadTranscriptAsync(this.rustService, transcript, this.mediaPath, reportingScope: null, CancellationToken.None)); + await Assert.ThrowsAsync(() => PersistentMediaTranscript.ReadTranscriptAsync(this.rustService, transcript, this.mediaPath, reportingScope: null, CancellationToken.None)); } [Test] diff --git a/app/Tests/Tools/PassageProvenanceTests.cs b/app/Tests/Tools/PassageProvenanceTests.cs index 1399abf6e..64565770a 100644 --- a/app/Tests/Tools/PassageProvenanceTests.cs +++ b/app/Tests/Tools/PassageProvenanceTests.cs @@ -117,12 +117,12 @@ public sealed class PassageProvenanceTests } [Test] - public void StoringNeverStopsTheAnswer() + public async Task StoringNeverStopsTheAnswer() { // A passage without its text, as an ERI server sent one before its fields were checked: var answer = new ContentText { SourcePassages = [Passage(HANDBOOK_URL, null!)] }; - Assert.DoesNotThrowAsync(() => answer.StoreReceivedContentAsync(Guid.NewGuid()), "Completing the answer waits for this, and a throw left its chat running until the app restarted."); + await Assert.DoesNotThrowAsync(() => answer.StoreReceivedContentAsync(Guid.NewGuid()), "Completing the answer waits for this, and a throw left its chat running until the app restarted."); } [Test] diff --git a/app/Tests/Tools/RetrievalPagingTests.cs b/app/Tests/Tools/RetrievalPagingTests.cs index 351e68c54..e22b57d1d 100644 --- a/app/Tests/Tools/RetrievalPagingTests.cs +++ b/app/Tests/Tools/RetrievalPagingTests.cs @@ -163,11 +163,11 @@ public sealed class RetrievalPagingTests } [Test] - public void AnERIDataSourceRefusesAFurtherPage() + public async Task AnERIDataSourceRefusesAFurtherPage() { var source = new DataSourceERI_V1 { Id = "33333333-3333-3333-3333-333333333333", Name = "Intranet", MaxMatches = 10 }; - Assert.ThrowsAsync(async () => await source.RetrieveDataAsync("query", 2, new AIStudio.Chat.ChatThread())); + await Assert.ThrowsAsync(async () => await source.RetrieveDataAsync("query", 2, new AIStudio.Chat.ChatThread())); } private static (IReadOnlyList Matches, bool HasMore) Merge(string[] first, string[] second, int page) diff --git a/app/Tests/Tools/ToolCalling/CountMailsToolTests.cs b/app/Tests/Tools/ToolCalling/CountMailsToolTests.cs index 4d5688664..e62080ae3 100644 --- a/app/Tests/Tools/ToolCalling/CountMailsToolTests.cs +++ b/app/Tests/Tools/ToolCalling/CountMailsToolTests.cs @@ -158,5 +158,5 @@ public sealed class CountMailsToolTests : ToolRegistryTestBase private static JsonElement Arguments(string json) => JsonSerializer.Deserialize(json); - private static string Refusal(TestDelegate read) => Assert.Throws(read)!.Message; + private static string Refusal(Action read) => Assert.Throws(read)!.Message; } \ No newline at end of file diff --git a/app/Tests/Tools/ToolCalling/MailToolArgumentsTests.cs b/app/Tests/Tools/ToolCalling/MailToolArgumentsTests.cs index 812f1c13e..c6dcb7908 100644 --- a/app/Tests/Tools/ToolCalling/MailToolArgumentsTests.cs +++ b/app/Tests/Tools/ToolCalling/MailToolArgumentsTests.cs @@ -223,7 +223,7 @@ public sealed class MailToolArgumentsTests private static JsonElement Arguments(string json) => JsonSerializer.Deserialize(json); - private static string Refusal(TestDelegate read) => Assert.Throws(read)!.Message; + private static string Refusal(Action read) => Assert.Throws(read)!.Message; /// /// A time zone two hours ahead of UTC, all year round, so that no test depends on the computer or on daylight saving time. diff --git a/app/Tests/Tools/ToolCalling/ReadMailToolTests.cs b/app/Tests/Tools/ToolCalling/ReadMailToolTests.cs index 3e5c12506..a732a35f8 100644 --- a/app/Tests/Tools/ToolCalling/ReadMailToolTests.cs +++ b/app/Tests/Tools/ToolCalling/ReadMailToolTests.cs @@ -194,5 +194,5 @@ public sealed class ReadMailToolTests : ToolRegistryTestBase private static JsonElement Arguments(string json) => JsonSerializer.Deserialize(json); - private static string Refusal(TestDelegate read) => Assert.Throws(read)!.Message; + private static string Refusal(Action read) => Assert.Throws(read)!.Message; } \ No newline at end of file diff --git a/app/Tests/Tools/ToolCalling/ReadWebPageAllowedPrivateHostTests.cs b/app/Tests/Tools/ToolCalling/ReadWebPageAllowedPrivateHostTests.cs index 708c0e3e6..69c13917e 100644 --- a/app/Tests/Tools/ToolCalling/ReadWebPageAllowedPrivateHostTests.cs +++ b/app/Tests/Tools/ToolCalling/ReadWebPageAllowedPrivateHostTests.cs @@ -149,11 +149,11 @@ public sealed class ReadWebPageAllowedPrivateHostTests : ToolRegistryTestBase } [Test] - public void AnAllowedNameWhichResolvesToAPublicAddressIsRefused() + public async Task AnAllowedNameWhichResolvesToAPublicAddressIsRefused() { var service = new WebPageRetrievalService(new HTMLParser()); - var exception = Assert.ThrowsAsync(() => service.RetrieveAsync(new Uri(PUBLIC_ADDRESS), new WebPageRetrievalOptions + var exception = await Assert.ThrowsAsync(() => service.RetrieveAsync(new Uri(PUBLIC_ADDRESS), new WebPageRetrievalOptions { TimeoutSeconds = 10, ProviderConfidence = ConfidenceLevel.HIGH, @@ -165,7 +165,7 @@ public sealed class ReadWebPageAllowedPrivateHostTests : ToolRegistryTestBase } [Test] - public void ARedirectFromAnAllowedPrivateHostToAPublicAddressIsRefused() + public async Task ARedirectFromAnAllowedPrivateHostToAPublicAddressIsRefused() { using var server = new LoopbackWebServer(redirectLocation: PUBLIC_ADDRESS); var service = new WebPageRetrievalService(new HTMLParser()); @@ -175,7 +175,7 @@ public sealed class ReadWebPageAllowedPrivateHostTests : ToolRegistryTestBase // chose only, which the limit holds for all the same, because it guards what the address // may carry: // - var exception = Assert.ThrowsAsync(() => service.RetrieveAsync(server.Address("/redirect"), new WebPageRetrievalOptions + var exception = await Assert.ThrowsAsync(() => service.RetrieveAsync(server.Address("/redirect"), new WebPageRetrievalOptions { TimeoutSeconds = 10, TargetChosenByUser = true, diff --git a/app/Tests/Tools/ToolCalling/ReadWebPageFreeAddressChoiceTests.cs b/app/Tests/Tools/ToolCalling/ReadWebPageFreeAddressChoiceTests.cs index 034e645c1..58786da2c 100644 --- a/app/Tests/Tools/ToolCalling/ReadWebPageFreeAddressChoiceTests.cs +++ b/app/Tests/Tools/ToolCalling/ReadWebPageFreeAddressChoiceTests.cs @@ -94,7 +94,7 @@ public sealed class ReadWebPageFreeAddressChoiceTests } [Test] - public void OffRefusesAMadeUpAddressWithoutRepeatingIt() + public async Task OffRefusesAMadeUpAddressWithoutRepeatingIt() { var tool = new ReadWebPageTool(null!, null!, null!, NullLogger.Instance); using var arguments = JsonDocument.Parse("""{"url":"https://made-up.example/?question=budget"}"""); @@ -109,7 +109,7 @@ public sealed class ReadWebPageFreeAddressChoiceTests SettingsValues = new Dictionary(), }; - var exception = Assert.ThrowsAsync(() => tool.ExecuteAsync(arguments.RootElement, context)); + var exception = await Assert.ThrowsAsync(() => tool.ExecuteAsync(arguments.RootElement, context)); Assert.That(exception!.Message, Does.Contain("Free address choice is off").And.Not.Contain("made-up").And.Not.Contain("budget"), "Repeated in the result, the address would stand in the chat afterwards."); } diff --git a/app/Tests/Tools/ToolCalling/ReadWebPageOutboundDataRestrictionTests.cs b/app/Tests/Tools/ToolCalling/ReadWebPageOutboundDataRestrictionTests.cs index 66603ff7d..231281637 100644 --- a/app/Tests/Tools/ToolCalling/ReadWebPageOutboundDataRestrictionTests.cs +++ b/app/Tests/Tools/ToolCalling/ReadWebPageOutboundDataRestrictionTests.cs @@ -87,7 +87,7 @@ public sealed class ReadWebPageOutboundDataRestrictionTests : ToolRegistryTestBa Assert.That(ReadWebPageTool.IsAllowedByOutboundDataRestriction(new Uri(GIVEN), (OutboundDataRestriction)99, ChatWithTheUserWriting(GIVEN), WIKI_URL, NO_PRIVATE_HOSTS, out _), Is.False); [Test] - public void ARefusalDoesNotRepeatTheAddress() + public async Task ARefusalDoesNotRepeatTheAddress() { // // Repeated in the result of a call, the address would stand in the chat afterwards, and the @@ -98,7 +98,7 @@ public sealed class ReadWebPageOutboundDataRestrictionTests : ToolRegistryTestBa var chat = RestrictedChat(OutboundDataRestriction.ONLY_LINKS_FROM_CHAT); using var arguments = JsonDocument.Parse("""{"url":"https://attacker.example/?mail=board-meeting"}"""); - var exception = Assert.ThrowsAsync(() => tool.ExecuteAsync(arguments.RootElement, this.ExecutionContext(tool, chat))); + var exception = await Assert.ThrowsAsync(() => tool.ExecuteAsync(arguments.RootElement, this.ExecutionContext(tool, chat))); Assert.That(exception!.Message, Does.Not.Contain("attacker").And.Not.Contain("board-meeting")); } diff --git a/app/Tests/Tools/ToolCalling/SearchMailsToolTests.cs b/app/Tests/Tools/ToolCalling/SearchMailsToolTests.cs index 6ef43e0c7..582b427a6 100644 --- a/app/Tests/Tools/ToolCalling/SearchMailsToolTests.cs +++ b/app/Tests/Tools/ToolCalling/SearchMailsToolTests.cs @@ -324,5 +324,5 @@ public sealed class SearchMailsToolTests : ToolRegistryTestBase private static JsonElement Arguments(string json) => JsonSerializer.Deserialize(json); - private static string Refusal(TestDelegate read) => Assert.Throws(read)!.Message; + private static string Refusal(Action read) => Assert.Throws(read)!.Message; } \ No newline at end of file diff --git a/app/Tests/Tools/ToolCalling/SemanticSearchToolRequestTests.cs b/app/Tests/Tools/ToolCalling/SemanticSearchToolRequestTests.cs index b3172553c..badfce6c1 100644 --- a/app/Tests/Tools/ToolCalling/SemanticSearchToolRequestTests.cs +++ b/app/Tests/Tools/ToolCalling/SemanticSearchToolRequestTests.cs @@ -115,5 +115,5 @@ public sealed class SemanticSearchToolRequestTests /// /// Reads a search which has to be refused and returns what the refusal said. /// - private static string Refusal(TestDelegate read) => Assert.Throws(read)!.Message; + private static string Refusal(Action read) => Assert.Throws(read)!.Message; } \ No newline at end of file diff --git a/app/Tests/Tools/ToolCalling/ToolArgumentReaderTests.cs b/app/Tests/Tools/ToolCalling/ToolArgumentReaderTests.cs index 7328da07d..e50aca2d3 100644 --- a/app/Tests/Tools/ToolCalling/ToolArgumentReaderTests.cs +++ b/app/Tests/Tools/ToolCalling/ToolArgumentReaderTests.cs @@ -163,5 +163,5 @@ public sealed class ToolArgumentReaderTests /// /// Runs a reader which has to refuse its argument and returns what it said. /// - private static string Refusal(TestDelegate read) => Assert.Throws(read)!.Message; + private static string Refusal(Action read) => Assert.Throws(read)!.Message; } \ No newline at end of file diff --git a/app/Tests/Tools/ToolCalling/WebSearchToolArgumentTests.cs b/app/Tests/Tools/ToolCalling/WebSearchToolArgumentTests.cs index 7e6675803..3a985bb90 100644 --- a/app/Tests/Tools/ToolCalling/WebSearchToolArgumentTests.cs +++ b/app/Tests/Tools/ToolCalling/WebSearchToolArgumentTests.cs @@ -166,5 +166,5 @@ public sealed class WebSearchToolArgumentTests /// /// Runs a reader which has to refuse its argument and returns what it said. /// - private static string Refusal(TestDelegate read) => Assert.Throws(read)!.Message; + private static string Refusal(Action read) => Assert.Throws(read)!.Message; } \ No newline at end of file