docs(tests): fix CommentChecker findings across tests/ — 13,392 → 0 (repo-wide scan clean)

Comment/XML-doc changes only:
- add summaries to ~10k test methods, fixtures, fakes and helpers
  (+ <param> on theories, <returns> on async Task methods,
  <inheritdoc/> on interface implementations the checker can resolve)
- strip ~2.6k project-tracking references (WP*, P*-*, row-NN, Task N,
  #NN, Component-0NN) from comments, keeping the explanatory text;
  reword false positives in comments only
- real docs on fakes implementing BCL/library interfaces
  (IDisposable, ILogger, IOptionsMonitor, IAsyncLifetime)
- reword the last 5 src/ false positives (CWE-1236, failures-1,
  year-0001, M365)

Only non-comment edits: four one-line nested classes split across lines
so members can carry docs. Build 0 errors / 0 warnings.
This commit is contained in:
Joseph Doherty
2026-10-07 15:05:49 -04:00
parent 0ffd4bdbea
commit 513fa1aa16
998 changed files with 17896 additions and 2395 deletions
@@ -4,6 +4,7 @@ namespace ZB.MOM.WW.ScadaBridge.NotificationOutbox.Tests.Delivery;
public class DeliveryOutcomeTests
{
/// <summary>Verifies that a success outcome carries the resolved targets and no error.</summary>
[Fact]
public void Success_SetsResolvedTargets_AndNoError()
{
@@ -14,6 +15,7 @@ public class DeliveryOutcomeTests
Assert.Null(outcome.Error);
}
/// <summary>Verifies that a transient outcome carries an error and no resolved targets.</summary>
[Fact]
public void Transient_SetsError_AndNoResolvedTargets()
{
@@ -24,6 +26,7 @@ public class DeliveryOutcomeTests
Assert.Null(outcome.ResolvedTargets);
}
/// <summary>Verifies that a permanent outcome carries an error and no resolved targets.</summary>
[Fact]
public void Permanent_SetsError_AndNoResolvedTargets()
{
@@ -11,7 +11,7 @@ using ZB.MOM.WW.ScadaBridge.NotificationService.Ews;
namespace ZB.MOM.WW.ScadaBridge.NotificationOutbox.Tests.Delivery;
/// <summary>
/// Task 5: Tests for the EWS transport branch of the Email outbox delivery adapter —
/// Tests for the EWS transport branch of the Email outbox delivery adapter —
/// the transport parse, the EWS config-shape validation (each failure permanent and
/// short-circuiting before the sender is touched), the request the sender receives,
/// the typed transient/permanent outcome mapping, and the proof that an unset or
@@ -100,6 +100,8 @@ public class EmailNotificationDeliveryAdapterEwsTests
Arg.Any<EwsSendRequest>(), Arg.Any<CancellationToken>());
}
/// <summary>Verifies that delivery over the EWS transport goes through the EWS sender and returns success.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Deliver_EwsTransport_SendsThroughEwsSenderAndReturnsSuccess()
{
@@ -129,6 +131,8 @@ public class EmailNotificationDeliveryAdapterEwsTests
Arg.Any<int>(), Arg.Any<CancellationToken>());
}
/// <summary>Verifies that credentials are split on the first colon only so a password may contain colons.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Deliver_PasswordContainsColon_SplitsOnFirstColonOnly()
{
@@ -143,6 +147,8 @@ public class EmailNotificationDeliveryAdapterEwsTests
Assert.Equal(DeliveryResult.Success, outcome.Result);
}
/// <summary>Verifies that a transient EWS exception maps to a transient outcome.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Deliver_EwsTransientException_ReturnsTransient()
{
@@ -157,6 +163,8 @@ public class EmailNotificationDeliveryAdapterEwsTests
Assert.Contains("server busy", outcome.Error);
}
/// <summary>Verifies that a permanent EWS exception maps to a permanent outcome.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Deliver_EwsPermanentException_ReturnsPermanent()
{
@@ -171,6 +179,8 @@ public class EmailNotificationDeliveryAdapterEwsTests
Assert.Contains("unauthorized", outcome.Error);
}
/// <summary>Verifies that an unclassified sender exception maps to a permanent outcome and redacts the credential.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Deliver_UnclassifiedSenderException_ReturnsPermanentAndRedactsCredential()
{
@@ -186,6 +196,8 @@ public class EmailNotificationDeliveryAdapterEwsTests
Assert.DoesNotContain("super-secret-password", outcome.Error);
}
/// <summary>Verifies that a cancelled token throws an operation-canceled exception.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Deliver_CancelledToken_ThrowsOperationCanceledException()
{
@@ -209,6 +221,8 @@ public class EmailNotificationDeliveryAdapterEwsTests
() => adapter.DeliverAsync(MakeNotification(), cts.Token));
}
/// <summary>Verifies that a non-HTTPS endpoint returns a permanent failure without calling the sender.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Deliver_NonHttpsEndpoint_ReturnsPermanentWithoutCallingSender()
{
@@ -222,6 +236,8 @@ public class EmailNotificationDeliveryAdapterEwsTests
await AssertSenderUntouched();
}
/// <summary>Verifies that a non-absolute endpoint returns a permanent failure without calling the sender.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Deliver_NonAbsoluteEndpoint_ReturnsPermanentWithoutCallingSender()
{
@@ -235,6 +251,8 @@ public class EmailNotificationDeliveryAdapterEwsTests
await AssertSenderUntouched();
}
/// <summary>Verifies that a non-basic auth type returns a permanent failure without calling the sender.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Deliver_NonBasicAuthType_ReturnsPermanentWithoutCallingSender()
{
@@ -248,6 +266,9 @@ public class EmailNotificationDeliveryAdapterEwsTests
await AssertSenderUntouched();
}
/// <summary>Verifies that malformed credentials return a permanent failure without calling the sender.</summary>
/// <param name="credentials">The malformed credentials string, or null.</param>
/// <returns>A task that represents the asynchronous operation.</returns>
[Theory]
[InlineData(null)]
[InlineData("")]
@@ -267,6 +288,8 @@ public class EmailNotificationDeliveryAdapterEwsTests
await AssertSenderUntouched();
}
/// <summary>Verifies that an unknown transport returns a permanent failure without calling the sender.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Deliver_UnknownTransport_ReturnsPermanentWithoutCallingSender()
{
@@ -283,6 +306,8 @@ public class EmailNotificationDeliveryAdapterEwsTests
Arg.Any<int>(), Arg.Any<CancellationToken>());
}
/// <summary>Verifies that delivery with no EWS sender registered returns a permanent failure.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Deliver_NoEwsSenderRegistered_ReturnsPermanent()
{
@@ -296,6 +321,9 @@ public class EmailNotificationDeliveryAdapterEwsTests
Assert.Contains("registered", outcome.Error);
}
/// <summary>Verifies that an SMTP or unset transport takes the SMTP path.</summary>
/// <param name="transport">The configured transport, or null when unset.</param>
/// <returns>A task that represents the asynchronous operation.</returns>
[Theory]
[InlineData(null)]
[InlineData("Smtp")]
@@ -13,7 +13,7 @@ using ZB.MOM.WW.ScadaBridge.NotificationService;
namespace ZB.MOM.WW.ScadaBridge.NotificationOutbox.Tests.Delivery;
/// <summary>
/// Task 12: Tests for the Email outbox delivery adapter — list/recipient/SMTP-config
/// Tests for the Email outbox delivery adapter — list/recipient/SMTP-config
/// resolution, SMTP send, and the three-way (Success / Permanent / Transient) outcome
/// classification.
/// </summary>
@@ -59,12 +59,15 @@ public class EmailNotificationDeliveryAdapterTests
_repository.GetAllSmtpConfigurationsAsync().Returns(new List<SmtpConfiguration> { smtpConfig });
}
/// <summary>Verifies that the adapter reports the Email notification type.</summary>
[Fact]
public void Type_IsEmail()
{
Assert.Equal(NotificationType.Email, CreateAdapter().Type);
}
/// <summary>Verifies that a successful delivery returns success with the resolved targets.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Deliver_HappyPath_ReturnsSuccessWithResolvedTargets()
{
@@ -80,6 +83,8 @@ public class EmailNotificationDeliveryAdapterTests
Assert.Null(outcome.Error);
}
/// <summary>Verifies that a missing notification list returns a permanent failure.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Deliver_ListNotFound_ReturnsPermanent()
{
@@ -93,6 +98,8 @@ public class EmailNotificationDeliveryAdapterTests
Assert.Contains("not found", outcome.Error);
}
/// <summary>Verifies that a list with no recipients returns a permanent failure.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Deliver_NoRecipients_ReturnsPermanent()
{
@@ -107,6 +114,8 @@ public class EmailNotificationDeliveryAdapterTests
Assert.Contains("recipient", outcome.Error);
}
/// <summary>Verifies that a missing SMTP configuration returns a permanent failure.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Deliver_NoSmtpConfig_ReturnsPermanent()
{
@@ -125,6 +134,8 @@ public class EmailNotificationDeliveryAdapterTests
Assert.Contains("SMTP", outcome.Error);
}
/// <summary>Verifies that a permanent SMTP exception returns a permanent failure.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Deliver_SmtpPermanentException_ReturnsPermanent()
{
@@ -141,6 +152,8 @@ public class EmailNotificationDeliveryAdapterTests
Assert.Contains("mailbox unavailable", outcome.Error);
}
/// <summary>Verifies that an SMTP 5xx command exception returns a permanent failure.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Deliver_Smtp5xxCommandException_ReturnsPermanent()
{
@@ -157,6 +170,8 @@ public class EmailNotificationDeliveryAdapterTests
Assert.Equal(DeliveryResult.PermanentFailure, outcome.Result);
}
/// <summary>Verifies that a socket exception returns a transient failure.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Deliver_SocketException_ReturnsTransient()
{
@@ -173,6 +188,8 @@ public class EmailNotificationDeliveryAdapterTests
Assert.NotNull(outcome.Error);
}
/// <summary>Verifies that an SMTP 4xx command exception returns a transient failure.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Deliver_Smtp4xxCommandException_ReturnsTransient()
{
@@ -189,6 +206,8 @@ public class EmailNotificationDeliveryAdapterTests
Assert.Equal(DeliveryResult.TransientFailure, outcome.Result);
}
/// <summary>Verifies that an unclassified exception returns a permanent failure.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Deliver_UnclassifiedException_ReturnsPermanent()
{
@@ -205,6 +224,8 @@ public class EmailNotificationDeliveryAdapterTests
Assert.NotNull(outcome.Error);
}
/// <summary>Verifies that a malformed recipient address returns a permanent failure.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Deliver_MalformedRecipientAddress_ReturnsPermanent()
{
@@ -230,6 +251,8 @@ public class EmailNotificationDeliveryAdapterTests
Assert.Contains(malformed, outcome.Error);
}
/// <summary>Verifies that a cancelled token throws an <c>OperationCanceledException</c>.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Deliver_CancelledToken_ThrowsOperationCanceledException()
{
@@ -265,6 +288,8 @@ public class EmailNotificationDeliveryAdapterTests
() => adapter.DeliverAsync(MakeNotification(), cts.Token));
}
/// <summary>Verifies that when several SMTP configurations exist the one with the lowest id wins.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task MultipleSmtpConfigs_LowestIdWins()
{
@@ -32,7 +32,9 @@ public class SmsNotificationDeliveryAdapterTests
{
private readonly Queue<Func<HttpRequestMessage, Task<HttpResponseMessage>>> _responders;
/// <summary>The HTTP requests received by the handler, in order.</summary>
public List<HttpRequestMessage> Requests { get; } = new();
/// <summary>The request bodies received by the handler, in order.</summary>
public List<string> RequestBodies { get; } = new();
private ScriptedHttpMessageHandler(IEnumerable<Func<HttpRequestMessage, Task<HttpResponseMessage>>> responders)
@@ -41,6 +43,8 @@ public class SmsNotificationDeliveryAdapterTests
}
/// <summary>One queued response per status code (one per recipient POST).</summary>
/// <param name="statusCodes">The status codes to queue, one per expected request.</param>
/// <returns>A handler that answers each request with the next queued status code.</returns>
public static ScriptedHttpMessageHandler ForStatuses(params HttpStatusCode[] statusCodes) =>
new(statusCodes.Select(code =>
new Func<HttpRequestMessage, Task<HttpResponseMessage>>(
@@ -50,9 +54,12 @@ public class SmsNotificationDeliveryAdapterTests
}))));
/// <summary>Custom per-request responders (e.g. to throw a transport exception).</summary>
/// <param name="responders">The responders to queue, one per expected request.</param>
/// <returns>A handler that answers each request with the next queued responder.</returns>
public static ScriptedHttpMessageHandler ForResponders(
params Func<HttpRequestMessage, Task<HttpResponseMessage>>[] responders) => new(responders);
/// <inheritdoc />
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
@@ -116,12 +123,15 @@ public class SmsNotificationDeliveryAdapterTests
});
}
/// <summary>Verifies that the adapter reports the SMS notification type.</summary>
[Fact]
public void Type_IsSms()
{
Assert.Equal(NotificationType.Sms, CreateAdapter(ScriptedHttpMessageHandler.ForStatuses()).Type);
}
/// <summary>Verifies that delivery to a single recipient with a 201 response succeeds and returns the resolved targets.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Deliver_SingleRecipient201_ReturnsSuccessWithResolvedTargets()
{
@@ -154,6 +164,8 @@ public class SmsNotificationDeliveryAdapterTests
_httpClientFactory.Received(1).CreateClient(SmsNotificationDeliveryAdapter.HttpClientName);
}
/// <summary>Verifies that delivery to several recipients that are all accepted succeeds.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Deliver_MultiRecipient201_AllAccepted_ReturnsSuccess()
{
@@ -169,6 +181,8 @@ public class SmsNotificationDeliveryAdapterTests
Assert.Equal(2, handler.Requests.Count);
}
/// <summary>Verifies that delivery uses the messaging service SID when no from number is configured.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Deliver_UsesMessagingServiceSid_WhenFromNumberAbsent()
{
@@ -191,6 +205,8 @@ public class SmsNotificationDeliveryAdapterTests
Assert.DoesNotContain("From=", body);
}
/// <summary>Verifies that a 500 response is classified as a transient failure.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Deliver_500_ReturnsTransient()
{
@@ -204,6 +220,8 @@ public class SmsNotificationDeliveryAdapterTests
Assert.NotNull(outcome.Error);
}
/// <summary>Verifies that a 429 response is classified as a transient failure.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Deliver_429_ReturnsTransient()
{
@@ -216,6 +234,8 @@ public class SmsNotificationDeliveryAdapterTests
Assert.Equal(DeliveryResult.TransientFailure, outcome.Result);
}
/// <summary>Verifies that an HTTP request exception is classified as a transient failure.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Deliver_HttpRequestException_ReturnsTransient()
{
@@ -229,6 +249,8 @@ public class SmsNotificationDeliveryAdapterTests
Assert.Equal(DeliveryResult.TransientFailure, outcome.Result);
}
/// <summary>Verifies that a timeout is classified as a transient failure.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Deliver_Timeout_ReturnsTransient()
{
@@ -244,6 +266,8 @@ public class SmsNotificationDeliveryAdapterTests
Assert.Equal(DeliveryResult.TransientFailure, outcome.Result);
}
/// <summary>Verifies that a 400 response is classified as a permanent failure.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Deliver_400_ReturnsPermanent()
{
@@ -257,6 +281,8 @@ public class SmsNotificationDeliveryAdapterTests
Assert.NotNull(outcome.Error);
}
/// <summary>Verifies that a 401 response is classified as a permanent failure.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Deliver_401_ReturnsPermanent()
{
@@ -269,6 +295,8 @@ public class SmsNotificationDeliveryAdapterTests
Assert.Equal(DeliveryResult.PermanentFailure, outcome.Result);
}
/// <summary>Verifies that a mix of accepted and permanently bad recipients succeeds and notes the bad number.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Deliver_MixAcceptedAndPermanentBad_ReturnsSuccessWithBadNumberNoted()
{
@@ -285,6 +313,8 @@ public class SmsNotificationDeliveryAdapterTests
Assert.Contains("+1BADNUMBER", outcome.ResolvedTargets);
}
/// <summary>Verifies that a mix of accepted and transiently failed recipients is classified as transient.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Deliver_MixAcceptedAndTransient_ReturnsTransient()
{
@@ -299,6 +329,8 @@ public class SmsNotificationDeliveryAdapterTests
Assert.Equal(DeliveryResult.TransientFailure, outcome.Result);
}
/// <summary>Verifies that a transient failure mid-list short-circuits so the remaining recipients are not attempted.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task MidListTransient_ShortCircuits_RemainingRecipientsNotAttempted()
{
@@ -317,6 +349,8 @@ public class SmsNotificationDeliveryAdapterTests
Assert.Single(handler.Requests);
}
/// <summary>Verifies that a missing notification list is classified as a permanent failure.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Deliver_ListNotFound_ReturnsPermanent()
{
@@ -331,6 +365,8 @@ public class SmsNotificationDeliveryAdapterTests
Assert.Contains("not found", outcome.Error);
}
/// <summary>Verifies that a list with no phone recipients is classified as a permanent failure.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Deliver_NoPhoneRecipients_ReturnsPermanent()
{
@@ -350,6 +386,8 @@ public class SmsNotificationDeliveryAdapterTests
Assert.Contains("no SMS recipients", outcome.Error);
}
/// <summary>Verifies that a missing SMS configuration is classified as a permanent failure.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Deliver_NoSmsConfig_ReturnsPermanent()
{
@@ -367,6 +405,8 @@ public class SmsNotificationDeliveryAdapterTests
Assert.Contains("SMS configuration", outcome.Error);
}
/// <summary>Verifies that an incomplete configuration missing the auth token is classified as a permanent failure.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Deliver_IncompleteConfig_MissingAuthToken_ReturnsPermanent()
{
@@ -385,6 +425,8 @@ public class SmsNotificationDeliveryAdapterTests
Assert.Contains("incomplete", outcome.Error);
}
/// <summary>Verifies that an incomplete configuration with neither a from number nor a messaging service SID is classified as a permanent failure.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Deliver_IncompleteConfig_NoFromAndNoMessagingServiceSid_ReturnsPermanent()
{
@@ -407,6 +449,8 @@ public class SmsNotificationDeliveryAdapterTests
Assert.Contains("incomplete", outcome.Error);
}
/// <summary>Verifies that delivery defaults to the Twilio base URL when no API base URL is configured.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Deliver_DefaultsToTwilioBaseUrl_WhenApiBaseUrlAbsent()
{
@@ -426,6 +470,8 @@ public class SmsNotificationDeliveryAdapterTests
Assert.StartsWith("https://api.twilio.com/2010-04-01/Accounts/", request.RequestUri!.ToString());
}
/// <summary>Verifies that the auth token never appears in a returned error.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Deliver_AuthToken_NeverAppearsInReturnedError()
{
@@ -457,6 +503,8 @@ public class SmsNotificationDeliveryAdapterTests
Assert.DoesNotContain(base64Credential, outcome.Error);
}
/// <summary>Verifies that the auth token never appears on a transport exception.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Deliver_AuthToken_NeverAppearsOnTransportException()
{
@@ -473,6 +521,8 @@ public class SmsNotificationDeliveryAdapterTests
Assert.DoesNotContain(AuthToken, outcome.Error);
}
/// <summary>Verifies that a long message body is truncated to the maximum message length.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Deliver_LongBody_TruncatedToMaxMessageLength()
{
@@ -495,6 +545,8 @@ public class SmsNotificationDeliveryAdapterTests
Assert.DoesNotContain(new string('x', 100), body);
}
/// <summary>Verifies that caller cancellation propagates out of delivery.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Deliver_CallerCancellation_Propagates()
{