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
@@ -11,7 +11,7 @@ using ZB.MOM.WW.ScadaBridge.Commons.Types.Enums;
namespace ZB.MOM.WW.ScadaBridge.AuditLog.Tests.Redaction;
/// <summary>
/// ScadaBridge audit re-architecture stage C2 (Task 2.5) tests for
/// ScadaBridge audit re-architecture stage C2 tests for
/// <see cref="ScadaBridgeAuditRedactor"/> — the canonical
/// <see cref="IAuditRedactor"/> implementation. Covers the header-redaction /
/// body-regex / SQL-param / safety-net / truncation pipeline operating on
@@ -20,6 +20,8 @@ namespace ZB.MOM.WW.ScadaBridge.AuditLog.Tests.Redaction;
/// </summary>
public class ScadaBridgeAuditRedactorTests
{
/// <summary>Verifies that every field of an error row is redacted and the error message is capped, whether the redactor is configured globally or per target.</summary>
/// <param name="perTarget">True to configure the redactor through a per-target override; false to configure it globally.</param>
[Theory]
[InlineData(false)]
[InlineData(true)]
@@ -35,6 +37,7 @@ public class ScadaBridgeAuditRedactorTests
Assert.True(Encoding.UTF8.GetByteCount(Details(result).ErrorMessage!) <= 128);
}
/// <summary>Verifies that the SQL parameter policy does not persist values echoed back in an exception message.</summary>
[Fact]
public void EI3_SqlParameterPolicy_DoesNotPersistExceptionEchoedValues()
{
@@ -101,6 +104,7 @@ public class ScadaBridgeAuditRedactorTests
// ---- Header redaction (ports HeaderRedactionTests) ---------------------
/// <summary>Verifies that an Authorization bearer header is redacted.</summary>
[Fact]
public void HeaderRedaction_AuthorizationBearer_Redacted()
{
@@ -116,6 +120,7 @@ public class ScadaBridgeAuditRedactorTests
Assert.Contains("application/json", d.RequestSummary);
}
/// <summary>Verifies that header redaction is case-insensitive, so a lowercase authorization header is redacted.</summary>
[Fact]
public void HeaderRedaction_CaseInsensitive_LowercaseAuthorization_Redacted()
{
@@ -127,6 +132,7 @@ public class ScadaBridgeAuditRedactorTests
Assert.Contains("\"authorization\":\"<redacted>\"", Details(result).RequestSummary!);
}
/// <summary>Verifies that a custom redact list redacts a custom header name.</summary>
[Fact]
public void HeaderRedaction_CustomRedactList_RedactsCustomHeaderName()
{
@@ -141,6 +147,7 @@ public class ScadaBridgeAuditRedactorTests
Assert.Contains("Bearer keep-me", d.RequestSummary!);
}
/// <summary>Verifies that a request summary that is not JSON passes through header redaction unchanged.</summary>
[Fact]
public void HeaderRedaction_NonJson_RequestSummary_Unchanged()
{
@@ -153,6 +160,7 @@ public class ScadaBridgeAuditRedactorTests
// ---- Body regex redaction (ports BodyRegexRedactionTests) --------------
/// <summary>Verifies that the global regex redacts a Hunter-style password value.</summary>
[Fact]
public void GlobalRegex_HunterPassword_Redacted()
{
@@ -170,6 +178,7 @@ public class ScadaBridgeAuditRedactorTests
Assert.Contains("alice", d.RequestSummary!);
}
/// <summary>Verifies that the body regex is applied to the error detail and the extra field.</summary>
[Fact]
public void BodyRegex_AppliesToErrorDetailAndExtra()
{
@@ -190,6 +199,7 @@ public class ScadaBridgeAuditRedactorTests
Assert.Contains("<redacted>", d.Extra!);
}
/// <summary>Verifies that a per-target regex is applied only to the matching target.</summary>
[Fact]
public void PerTargetRegex_OnlyAppliedToMatchingTarget()
{
@@ -213,6 +223,7 @@ public class ScadaBridgeAuditRedactorTests
Assert.Equal(input, Details(unmatched).RequestSummary);
}
/// <summary>Verifies that a field is left unchanged when no regex is configured.</summary>
[Fact]
public void NoRegexConfigured_FieldUnchanged()
{
@@ -223,6 +234,7 @@ public class ScadaBridgeAuditRedactorTests
Assert.Equal("{\"password\":\"hunter2\"}", Details(result).RequestSummary);
}
/// <summary>Verifies that a regex that times out turns the field into the redacted marker and increments the failure counter.</summary>
[Fact]
public void RegexThrowsTimeout_FieldBecomesRedactedMarker_CounterIncrements()
{
@@ -257,6 +269,7 @@ public class ScadaBridgeAuditRedactorTests
return sb.ToString();
}
/// <summary>Verifies that SQL parameters are kept verbatim when no opt-in is configured.</summary>
[Fact]
public void NoOptIn_ParamsVerbatim_Unchanged()
{
@@ -272,6 +285,7 @@ public class ScadaBridgeAuditRedactorTests
Assert.Equal(input, Details(result).RequestSummary);
}
/// <summary>Verifies that an opt-in regex on parameter names redacts the matching values and keeps the others.</summary>
[Fact]
public void OptInRegex_AtToken_RedactsThoseValues_KeepsOthers()
{
@@ -298,6 +312,7 @@ public class ScadaBridgeAuditRedactorTests
Assert.DoesNotContain("k-987", d.RequestSummary!);
}
/// <summary>Verifies that a channel other than database-outbound is not affected by the SQL parameter policy.</summary>
[Fact]
public void NonDbOutboundChannel_NotAffected()
{
@@ -320,6 +335,7 @@ public class ScadaBridgeAuditRedactorTests
// ---- Truncation + cap selection (ports TruncationTests) ----------------
/// <summary>Verifies that a 10 KB request summary on a success row is truncated to 8 KB and flagged as payload-truncated.</summary>
[Fact]
public void SuccessRow_10KB_RequestSummary_TruncatedTo8KB_PayloadTruncatedTrue()
{
@@ -334,6 +350,7 @@ public class ScadaBridgeAuditRedactorTests
Assert.True(d.PayloadTruncated);
}
/// <summary>Verifies that a 10 KB request summary on a failed row is not truncated because it is under the error cap.</summary>
[Fact]
public void ErrorRow_Failed_10KB_RequestSummary_NotTruncated_UnderErrorCap()
{
@@ -348,6 +365,7 @@ public class ScadaBridgeAuditRedactorTests
Assert.False(d.PayloadTruncated);
}
/// <summary>Verifies that a 70 KB request summary on a failed row is truncated to 64 KB.</summary>
[Fact]
public void ErrorRow_Failed_70KB_RequestSummary_TruncatedTo64KB()
{
@@ -362,6 +380,7 @@ public class ScadaBridgeAuditRedactorTests
Assert.True(d.PayloadTruncated);
}
/// <summary>Verifies that an attempted status is treated as an error and uses the error cap even though the outcome is success.</summary>
[Fact]
public void StatusAttempted_TreatedAsError_UsesErrorCap_EvenThoughOutcomeSuccess()
{
@@ -379,6 +398,7 @@ public class ScadaBridgeAuditRedactorTests
Assert.False(d.PayloadTruncated);
}
/// <summary>Verifies that a skipped status is treated as an error and uses the error cap even though the outcome is success.</summary>
[Fact]
public void StatusSkipped_TreatedAsError_UsesErrorCap_EvenThoughOutcomeSuccess()
{
@@ -391,6 +411,7 @@ public class ScadaBridgeAuditRedactorTests
Assert.False(Details(result).PayloadTruncated);
}
/// <summary>Verifies that a submitted status is treated as a success and uses the default cap.</summary>
[Fact]
public void StatusSubmitted_TreatedAsSuccess_UsesDefaultCap()
{
@@ -406,6 +427,7 @@ public class ScadaBridgeAuditRedactorTests
Assert.True(d.PayloadTruncated);
}
/// <summary>Verifies that a large inbound API body uses the inbound cap rather than the default cap.</summary>
[Fact]
public void ApiInbound_LargeBody_UsesInboundCap_NotDefault()
{
@@ -420,6 +442,7 @@ public class ScadaBridgeAuditRedactorTests
Assert.Equal(100_000, Encoding.UTF8.GetByteCount(d.RequestSummary!));
}
/// <summary>Verifies that a failed inbound API body above the inbound maximum is truncated to that maximum.</summary>
[Fact]
public void ApiInbound_Failed_BodyAboveInboundMaxBytes_TruncatedToInboundMaxBytes()
{
@@ -435,6 +458,7 @@ public class ScadaBridgeAuditRedactorTests
Assert.True(Encoding.UTF8.GetByteCount(d.ResponseSummary!) <= 16_384);
}
/// <summary>Verifies that multibyte UTF-8 text is truncated at a character boundary rather than in the middle of a byte sequence.</summary>
[Fact]
public void Multibyte_UTF8_TruncatedAtCharacterBoundary_NotMidByte()
{
@@ -453,6 +477,7 @@ public class ScadaBridgeAuditRedactorTests
Assert.True(d.PayloadTruncated);
}
/// <summary>Verifies that a details payload that was already marked truncated stays truncated.</summary>
[Fact]
public void ExistingDetailsPayloadTruncated_RemainsTrue()
{
@@ -467,6 +492,7 @@ public class ScadaBridgeAuditRedactorTests
// ---- Target length cap -------------------------------------------------
/// <summary>Verifies that a target over the cap is truncated at a byte boundary.</summary>
[Fact]
public void Target_OverCap_Truncated_ToByteBoundary()
{
@@ -483,6 +509,7 @@ public class ScadaBridgeAuditRedactorTests
// ---- Fast-path ---------------------------------------------------------
/// <summary>Verifies that the fast path returns the same instance when the details are null and the target is short.</summary>
[Fact]
public void FastPath_NullDetailsAndShortTarget_ReturnsSameInstance()
{
@@ -502,6 +529,7 @@ public class ScadaBridgeAuditRedactorTests
Assert.Same(evt, result);
}
/// <summary>Verifies that the fast path returns the same instance when the details are empty and the target is short.</summary>
[Fact]
public void FastPath_EmptyDetailsAndShortTarget_ReturnsSameInstance()
{
@@ -523,6 +551,7 @@ public class ScadaBridgeAuditRedactorTests
// ---- Never-throws safety net -------------------------------------------
/// <summary>Verifies that malformed details JSON never throws and yields a safe copy.</summary>
[Fact]
public void MalformedDetailsJson_NeverThrows_ReturnsSafeCopy()
{
@@ -545,6 +574,7 @@ public class ScadaBridgeAuditRedactorTests
Assert.Null(ex);
}
/// <summary>Verifies that a fault thrown by the options monitor never leaks sensitive values, because the outer catch over-redacts every sensitive field.</summary>
[Fact]
public void OuterCatch_OptionsThrows_NeverLeaks_AllSensitiveFieldsOverRedacted()
{
@@ -601,7 +631,9 @@ public class ScadaBridgeAuditRedactorTests
private sealed class CountingRedactionFailureCounter : IAuditRedactionFailureCounter
{
private int _count;
/// <summary>Gets the number of recorded failures.</summary>
public int Count => _count;
/// <inheritdoc />
public void Increment() => System.Threading.Interlocked.Increment(ref _count);
}
@@ -609,9 +641,18 @@ public class ScadaBridgeAuditRedactorTests
private sealed class StaticMonitor : IOptionsMonitor<AuditLogOptions>
{
private readonly AuditLogOptions _value;
/// <summary>Initializes a new instance of the <see cref="StaticMonitor"/> class.</summary>
/// <param name="value">The options snapshot returned on every read.</param>
public StaticMonitor(AuditLogOptions value) => _value = value;
/// <summary>Gets the options value this monitor serves.</summary>
public AuditLogOptions CurrentValue => _value;
/// <summary>Returns the options value regardless of name.</summary>
/// <param name="name">The options name (ignored).</param>
/// <returns>The options value.</returns>
public AuditLogOptions Get(string? name) => _value;
/// <summary>Ignores the listener; the options never change.</summary>
/// <param name="listener">The change listener (ignored).</param>
/// <returns>Always null.</returns>
public IDisposable? OnChange(Action<AuditLogOptions, string?> listener) => null;
}
@@ -622,9 +663,16 @@ public class ScadaBridgeAuditRedactorTests
/// </summary>
private sealed class ThrowingMonitor : IOptionsMonitor<AuditLogOptions>
{
/// <summary>Gets the options value this monitor serves.</summary>
public AuditLogOptions CurrentValue =>
throw new InvalidOperationException("Simulated options fault for outer-catch test");
/// <summary>Returns the options value regardless of name.</summary>
/// <param name="name">The options name (ignored).</param>
/// <returns>The options value.</returns>
public AuditLogOptions Get(string? name) => new AuditLogOptions();
/// <summary>Ignores the listener; the options never change.</summary>
/// <param name="listener">The change listener (ignored).</param>
/// <returns>Always null.</returns>
public IDisposable? OnChange(Action<AuditLogOptions, string?> listener) => null;
}
}