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:
@@ -23,6 +23,8 @@ public class OAuth2TokenServiceTests
|
||||
return factory;
|
||||
}
|
||||
|
||||
/// <summary>Verifies that get token async returns access token from token endpoint.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task GetTokenAsync_ReturnsAccessToken_FromTokenEndpoint()
|
||||
{
|
||||
@@ -42,6 +44,8 @@ public class OAuth2TokenServiceTests
|
||||
Assert.Equal("mock-access-token-12345", token);
|
||||
}
|
||||
|
||||
/// <summary>Verifies that get token async caches token on subsequent calls.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task GetTokenAsync_CachesToken_OnSubsequentCalls()
|
||||
{
|
||||
@@ -65,6 +69,8 @@ public class OAuth2TokenServiceTests
|
||||
Assert.Equal(1, handler.CallCount); // Only one HTTP call should be made
|
||||
}
|
||||
|
||||
/// <summary>Verifies that get token async invalid credential format throws invalid operation exception.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task GetTokenAsync_InvalidCredentialFormat_ThrowsInvalidOperationException()
|
||||
{
|
||||
@@ -76,6 +82,8 @@ public class OAuth2TokenServiceTests
|
||||
() => service.GetTokenAsync("invalid-no-colons"));
|
||||
}
|
||||
|
||||
/// <summary>Verifies that get token async http failure throws http request exception.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task GetTokenAsync_HttpFailure_ThrowsHttpRequestException()
|
||||
{
|
||||
@@ -87,12 +95,14 @@ public class OAuth2TokenServiceTests
|
||||
() => service.GetTokenAsync("tenant:client:secret"));
|
||||
}
|
||||
|
||||
// ── NotificationService-006: token cache must be keyed to credential identity ──
|
||||
// ── Token cache must be keyed to credential identity ──
|
||||
|
||||
/// <summary>Verifies that get token async different credentials return per credential tokens.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task GetTokenAsync_DifferentCredentials_ReturnPerCredentialTokens()
|
||||
{
|
||||
// NS-006: the singleton cached a single token ignoring the credentials
|
||||
// The singleton cached a single token ignoring the credentials
|
||||
// argument, so a second SMTP config with a different tenant/client got the
|
||||
// first config's token. Each distinct credential must get its own token.
|
||||
var handler = new PerTenantHttpMessageHandler();
|
||||
@@ -107,10 +117,12 @@ public class OAuth2TokenServiceTests
|
||||
Assert.Equal("token-for-tenantB", tokenB);
|
||||
}
|
||||
|
||||
/// <summary>Verifies that get token async same credentials cached per credential.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task GetTokenAsync_SameCredentials_CachedPerCredential()
|
||||
{
|
||||
// NS-006: caching still works — repeated calls with the same credential
|
||||
// Caching still works — repeated calls with the same credential
|
||||
// identity make exactly one HTTP call.
|
||||
var handler = new PerTenantHttpMessageHandler();
|
||||
var client = new HttpClient(handler);
|
||||
@@ -124,12 +136,14 @@ public class OAuth2TokenServiceTests
|
||||
Assert.Equal(2, handler.CallCount); // one per distinct credential, not per call
|
||||
}
|
||||
|
||||
// ── NotificationService-012: token expiry/refresh and concurrent acquisition ──
|
||||
// ── Token expiry/refresh and concurrent acquisition ──
|
||||
|
||||
/// <summary>Verifies that get token async expired token refreshes on next call.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task GetTokenAsync_ExpiredToken_RefreshesOnNextCall()
|
||||
{
|
||||
// NS-012: token expiry/refresh was untested — the cache test used a 3600s
|
||||
// Token expiry/refresh was untested — the cache test used a 3600s
|
||||
// token so the refresh branch never ran. The service refreshes 60s before
|
||||
// the stated expiry, so an expires_in of 60 makes the token immediately
|
||||
// stale and the next call must fetch a fresh one.
|
||||
@@ -148,10 +162,12 @@ public class OAuth2TokenServiceTests
|
||||
Assert.Equal(2, handler.CallCount);
|
||||
}
|
||||
|
||||
/// <summary>Verifies that get token async concurrent calls make exactly one http request.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task GetTokenAsync_ConcurrentCalls_MakeExactlyOneHttpRequest()
|
||||
{
|
||||
// NS-012: the double-checked-locking path was never exercised. Many callers
|
||||
// The double-checked-locking path was never exercised. Many callers
|
||||
// racing for the same uncached credential must collapse to a single token
|
||||
// fetch, not one HTTP call per caller.
|
||||
var handler = new SlowCountingHttpMessageHandler(
|
||||
@@ -169,12 +185,14 @@ public class OAuth2TokenServiceTests
|
||||
Assert.Equal(1, handler.CallCount);
|
||||
}
|
||||
|
||||
// ── Task 19: configurable OAuth2 authority + scope per SMTP configuration ──
|
||||
// ── Configurable OAuth2 authority + scope per SMTP configuration ──
|
||||
|
||||
/// <summary>Verifies that get token async custom authority and scope posts to configured endpoint.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task GetTokenAsync_CustomAuthorityAndScope_PostsToConfiguredEndpoint()
|
||||
{
|
||||
// A non-M365 IdP: the stored authority template carries a {tenant} placeholder
|
||||
// An IdP other than Microsoft 365: the stored authority template carries a {tenant} placeholder
|
||||
// and the scope is provider-specific. Both must flow verbatim into the request.
|
||||
var handler = new CapturingHttpMessageHandler(
|
||||
TokenJson("custom-token", expiresIn: 3600));
|
||||
@@ -192,6 +210,8 @@ public class OAuth2TokenServiceTests
|
||||
Assert.Equal("smtp.send", handler.LastForm!["scope"]);
|
||||
}
|
||||
|
||||
/// <summary>Verifies that get token async preserves the Microsoft 365 defaults.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task GetTokenAsync_DefaultsPreserved_M365()
|
||||
{
|
||||
@@ -223,10 +243,14 @@ public class OAuth2TokenServiceTests
|
||||
private class SequenceHttpMessageHandler : HttpMessageHandler
|
||||
{
|
||||
private readonly string[] _responses;
|
||||
/// <summary>The number of HTTP requests the handler has served.</summary>
|
||||
public int CallCount { get; private set; }
|
||||
|
||||
/// <summary>Initializes a new instance of <c>SequenceHttpMessageHandler</c>.</summary>
|
||||
/// <param name="responses">The responses.</param>
|
||||
public SequenceHttpMessageHandler(params string[] responses) => _responses = responses;
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override Task<HttpResponseMessage> SendAsync(
|
||||
HttpRequestMessage request, CancellationToken cancellationToken)
|
||||
{
|
||||
@@ -245,14 +269,19 @@ public class OAuth2TokenServiceTests
|
||||
private readonly string _response;
|
||||
private readonly TimeSpan _delay;
|
||||
private int _callCount;
|
||||
/// <summary>The number of HTTP requests the handler has served.</summary>
|
||||
public int CallCount => _callCount;
|
||||
|
||||
/// <summary>Initializes a new instance of <c>SlowCountingHttpMessageHandler</c>.</summary>
|
||||
/// <param name="response">The response.</param>
|
||||
/// <param name="delay">The delay.</param>
|
||||
public SlowCountingHttpMessageHandler(string response, TimeSpan delay)
|
||||
{
|
||||
_response = response;
|
||||
_delay = delay;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override async Task<HttpResponseMessage> SendAsync(
|
||||
HttpRequestMessage request, CancellationToken cancellationToken)
|
||||
{
|
||||
@@ -271,8 +300,10 @@ public class OAuth2TokenServiceTests
|
||||
/// </summary>
|
||||
private class PerTenantHttpMessageHandler : HttpMessageHandler
|
||||
{
|
||||
/// <summary>The number of HTTP requests the handler has served.</summary>
|
||||
public int CallCount { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override Task<HttpResponseMessage> SendAsync(
|
||||
HttpRequestMessage request, CancellationToken cancellationToken)
|
||||
{
|
||||
@@ -299,11 +330,16 @@ public class OAuth2TokenServiceTests
|
||||
private class CapturingHttpMessageHandler : HttpMessageHandler
|
||||
{
|
||||
private readonly string _response;
|
||||
/// <summary>The URI of the most recent request, if any.</summary>
|
||||
public Uri? LastRequestUri { get; private set; }
|
||||
/// <summary>The form fields posted in the most recent request, if any.</summary>
|
||||
public IReadOnlyDictionary<string, string>? LastForm { get; private set; }
|
||||
|
||||
/// <summary>Initializes a new instance of <c>CapturingHttpMessageHandler</c>.</summary>
|
||||
/// <param name="response">The response.</param>
|
||||
public CapturingHttpMessageHandler(string response) => _response = response;
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override async Task<HttpResponseMessage> SendAsync(
|
||||
HttpRequestMessage request, CancellationToken cancellationToken)
|
||||
{
|
||||
@@ -332,12 +368,16 @@ public class OAuth2TokenServiceTests
|
||||
private readonly HttpStatusCode _statusCode;
|
||||
private readonly string _responseContent;
|
||||
|
||||
/// <summary>Initializes a new instance of <c>MockHttpMessageHandler</c>.</summary>
|
||||
/// <param name="statusCode">The status code.</param>
|
||||
/// <param name="responseContent">The response content.</param>
|
||||
public MockHttpMessageHandler(HttpStatusCode statusCode, string responseContent)
|
||||
{
|
||||
_statusCode = statusCode;
|
||||
_responseContent = responseContent;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override Task<HttpResponseMessage> SendAsync(
|
||||
HttpRequestMessage request, CancellationToken cancellationToken)
|
||||
{
|
||||
@@ -355,14 +395,19 @@ public class OAuth2TokenServiceTests
|
||||
{
|
||||
private readonly HttpStatusCode _statusCode;
|
||||
private readonly string _responseContent;
|
||||
/// <summary>The number of HTTP requests the handler has served.</summary>
|
||||
public int CallCount { get; private set; }
|
||||
|
||||
/// <summary>Initializes a new instance of <c>CountingHttpMessageHandler</c>.</summary>
|
||||
/// <param name="statusCode">The status code.</param>
|
||||
/// <param name="responseContent">The response content.</param>
|
||||
public CountingHttpMessageHandler(HttpStatusCode statusCode, string responseContent)
|
||||
{
|
||||
_statusCode = statusCode;
|
||||
_responseContent = responseContent;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override Task<HttpResponseMessage> SendAsync(
|
||||
HttpRequestMessage request, CancellationToken cancellationToken)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user