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
@@ -10,8 +10,7 @@ using ZB.MOM.WW.ScadaBridge.Commons.Types.Enums;
namespace ZB.MOM.WW.ScadaBridge.AuditLog.Tests.Redaction;
/// <summary>
/// Guards the fail-closed contract for unavailable redactor patterns
/// (Gitea #35).
/// Guards the fail-closed contract for unavailable redactor patterns.
///
/// <para>
/// <b>The defect.</b> <see cref="AuditRegexCache"/> rejects a pattern that is
@@ -118,6 +117,7 @@ public class AuditRedactorFailClosedTests
Assert.Equal(0, counter.Count);
}
/// <summary>Verifies that an unavailable global body redactor suppresses the payload rather than emitting it raw.</summary>
[Fact]
public void UnavailableGlobalBodyRedactor_SuppressesPayload_RatherThanEmittingItRaw()
{
@@ -152,6 +152,7 @@ public class AuditRedactorFailClosedTests
Assert.Equal(1, counter.Count);
}
/// <summary>Verifies that an unavailable per-target body redactor suppresses the payload.</summary>
[Fact]
public void UnavailablePerTargetBodyRedactor_SuppressesPayload()
{
@@ -267,16 +268,27 @@ public class AuditRedactorFailClosedTests
private sealed class CountingCounter : IAuditRedactionFailureCounter
{
private int _count;
/// <summary>Gets the number of redaction failures counted so far.</summary>
public int Count => Volatile.Read(ref _count);
/// <inheritdoc />
public void Increment() => Interlocked.Increment(ref _count);
}
private sealed class StaticMonitor : IOptionsMonitor<AuditLogOptions>
{
private readonly AuditLogOptions _value;
/// <summary>Initializes the monitor with a fixed options value.</summary>
/// <param name="value">The value.</param>
public StaticMonitor(AuditLogOptions value) => _value = value;
/// <summary>Gets the current options value.</summary>
public AuditLogOptions CurrentValue => _value;
/// <summary>Returns the current options value regardless of the name.</summary>
/// <param name="name">The options name; ignored.</param>
/// <returns>The current options value.</returns>
public AuditLogOptions Get(string? name) => _value;
/// <summary>Registers a listener to be notified when the options change.</summary>
/// <param name="listener">The change callback.</param>
/// <returns>A disposable that removes the listener, or null when none is tracked.</returns>
public IDisposable? OnChange(Action<AuditLogOptions, string?> listener) => null;
}
@@ -286,10 +298,14 @@ public class AuditRedactorFailClosedTests
private readonly List<Action<AuditLogOptions, string?>> _listeners = new();
private int _reads;
/// <summary>Initializes the monitor with an initial options value.</summary>
/// <param name="value">The value.</param>
public MutableMonitor(AuditLogOptions value) => _value = value;
/// <summary>Gets the number of times <c>CurrentValue</c> has been read.</summary>
public int CurrentValueReads => Volatile.Read(ref _reads);
/// <summary>Gets the current options value.</summary>
public AuditLogOptions CurrentValue
{
get
@@ -299,8 +315,14 @@ public class AuditRedactorFailClosedTests
}
}
/// <summary>Gets the current options value.</summary>
/// <param name="name">The options name (ignored).</param>
/// <returns>The current options value.</returns>
public AuditLogOptions Get(string? name) => CurrentValue;
/// <summary>Registers a listener to be notified when the options change.</summary>
/// <param name="listener">The change callback.</param>
/// <returns>A disposable that removes the listener, or null when none is tracked.</returns>
public IDisposable? OnChange(Action<AuditLogOptions, string?> listener)
{
lock (_listeners)
@@ -310,6 +332,8 @@ public class AuditRedactorFailClosedTests
return new Noop();
}
/// <summary>Replaces the current options value and notifies every registered listener.</summary>
/// <param name="value">The value.</param>
public void Set(AuditLogOptions value)
{
_value = value;
@@ -326,6 +350,7 @@ public class AuditRedactorFailClosedTests
private sealed class Noop : IDisposable
{
/// <summary>Releases the resources held by the test fixture.</summary>
public void Dispose() { }
}
}
@@ -5,7 +5,7 @@ using ZB.MOM.WW.ScadaBridge.Commons.Types.Audit;
namespace ZB.MOM.WW.ScadaBridge.AuditLog.Tests.Redaction;
/// <summary>
/// ScadaBridge audit re-architecture stage C2 (Task 2.5) tests for
/// Tests for
/// <see cref="SafeDefaultAuditRedactor"/> — the minimal always-safe
/// <see cref="ZB.MOM.WW.Audit.IAuditRedactor"/> fallback.
/// Header-only scrub of the always-sensitive default headers inside
@@ -35,6 +35,7 @@ public class SafeDefaultAuditRedactorTests
private static AuditDetails Details(AuditEvent evt) =>
AuditDetailsCodec.Deserialize(evt.DetailsJson);
/// <summary>Verifies that the default sensitive headers are redacted in the request summary.</summary>
[Fact]
public void Redacts_DefaultSensitiveHeaders_InRequestSummary()
{
@@ -48,6 +49,7 @@ public class SafeDefaultAuditRedactorTests
Assert.Contains("Content-Type: application/json", d.RequestSummary!);
}
/// <summary>Verifies that the default sensitive headers are redacted in the response summary.</summary>
[Fact]
public void Redacts_DefaultSensitiveHeaders_InResponseSummary()
{
@@ -61,6 +63,7 @@ public class SafeDefaultAuditRedactorTests
Assert.Contains("X-Other: ok", d.ResponseSummary!);
}
/// <summary>Verifies that header names are matched case-insensitively when redacting.</summary>
[Fact]
public void CaseInsensitive_HeaderName_Redacted()
{
@@ -72,6 +75,7 @@ public class SafeDefaultAuditRedactorTests
Assert.DoesNotContain("x-y-z", Details(result).RequestSummary!);
}
/// <summary>Verifies that a non-sensitive header is preserved unchanged.</summary>
[Fact]
public void NonSensitiveHeader_Preserved()
{
@@ -84,6 +88,7 @@ public class SafeDefaultAuditRedactorTests
Assert.Contains("Accept: application/json", d.RequestSummary!);
}
/// <summary>Verifies that an event with null details takes the fast path and returns the same instance.</summary>
[Fact]
public void NullDetails_FastPath_ReturnsSameInstance()
{
@@ -102,6 +107,7 @@ public class SafeDefaultAuditRedactorTests
Assert.Same(evt, result);
}
/// <summary>Verifies that malformed details JSON never causes the redactor to throw.</summary>
[Fact]
public void MalformedDetailsJson_NeverThrows()
{
@@ -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;
}
}