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
@@ -24,7 +24,7 @@ using TransportImportPage = ZB.MOM.WW.ScadaBridge.CentralUI.Components.Pages.Des
namespace ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Pages.Design;
/// <summary>
/// bUnit + logic tests for the TransportImport wizard (Component #24, Task T22).
/// bUnit + logic tests for the TransportImport wizard.
///
/// <para>
/// The wizard has five steps (Upload / Passphrase / Diff / Confirm / Result).
@@ -41,7 +41,7 @@ public class TransportImportPageTests : BunitContext
{
private readonly IBundleImporter _importer = Substitute.For<IBundleImporter>();
private readonly IAuditService _auditService = Substitute.For<IAuditService>();
// M8 E2: the Map step injects ISiteRepository to populate target-site +
// The Map step injects ISiteRepository to populate target-site +
// target-connection dropdowns. Register a substitute so every test (not just
// the Map tests) can render the wizard without a missing-service failure.
private readonly ISiteRepository _siteRepo = Substitute.For<ISiteRepository>();
@@ -49,6 +49,7 @@ public class TransportImportPageTests : BunitContext
/// <summary>Client address the wizard reports for the per-IP unlock throttle (register row 44).</summary>
private const string TestClientIp = "203.0.113.7";
/// <summary>Initializes the test context with stubbed importer, audit, repository and authentication services.</summary>
public TransportImportPageTests()
{
JSInterop.Mode = JSRuntimeMode.Loose;
@@ -124,6 +125,7 @@ public class TransportImportPageTests : BunitContext
// ─────────────────────────────────────────────────────────────────────
// Test 1: Step 1 renders the InputFile upload control.
// ─────────────────────────────────────────────────────────────────────
/// <summary>Verifies that the wizard renders the step 1 upload input.</summary>
[Fact]
public void Renders_step1_upload_input()
{
@@ -138,6 +140,8 @@ public class TransportImportPageTests : BunitContext
// Test 2: Wrong passphrase increments the failure counter without
// advancing past Step 2.
// ─────────────────────────────────────────────────────────────────────
/// <summary>Verifies that a decryption failure increments the passphrase attempt counter.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Decryption_failure_increments_attempt_counter()
{
@@ -169,6 +173,8 @@ public class TransportImportPageTests : BunitContext
// Test 3: After MaxUnlockAttemptsPerSession failures the wizard returns
// to Step 1 with an explanatory error.
// ─────────────────────────────────────────────────────────────────────
/// <summary>Verifies that three failed unlock attempts force the user to upload the bundle again.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Three_failed_unlocks_force_reupload()
{
@@ -202,6 +208,8 @@ public class TransportImportPageTests : BunitContext
// Test 4: Confirm step requires an exact match (case-sensitive) on the
// source environment name before Apply is enabled.
// ─────────────────────────────────────────────────────────────────────
/// <summary>Verifies that the confirm step requires an exact environment name match.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Confirm_step_requires_exact_environment_name_match()
{
@@ -250,6 +258,8 @@ public class TransportImportPageTests : BunitContext
// Test 5: ApplyAsync is invoked with the chosen resolutions and the
// authenticated user identity.
// ─────────────────────────────────────────────────────────────────────
/// <summary>Verifies that the apply step calls the bundle importer's <c>ApplyAsync</c> with the chosen resolutions.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Apply_step_invokes_BundleImporter_ApplyAsync_with_resolutions()
{
@@ -314,6 +324,8 @@ public class TransportImportPageTests : BunitContext
// doesn't model routing, so we verify the policy itself denies the
// principal.
// ─────────────────────────────────────────────────────────────────────
/// <summary>Verifies that the page is unauthorized for a user without the Admin role.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Page_returns_unauthorized_for_user_without_Admin_role()
{
@@ -335,6 +347,7 @@ public class TransportImportPageTests : BunitContext
// Test 7 (helper coverage): BuildDefaultResolutions maps each kind to the
// expected default ResolutionAction.
// ─────────────────────────────────────────────────────────────────────
/// <summary>Verifies that default resolutions map each conflict kind to the expected action.</summary>
[Fact]
public void BuildDefaultResolutions_maps_kinds_to_actions()
{
@@ -355,10 +368,12 @@ public class TransportImportPageTests : BunitContext
}
// ─────────────────────────────────────────────────────────────────────
// Test 8 (M8 E2): the Map sub-section renders one row per required site /
// Test 8: the Map sub-section renders one row per required site /
// connection mapping with the auto-match defaults pre-selected, and the
// section is hidden entirely when the preview carries no required mappings.
// ─────────────────────────────────────────────────────────────────────
/// <summary>Verifies that the map section renders the required rows with auto-match defaults selected.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Map_section_renders_required_rows_with_automatch_defaults()
{
@@ -398,6 +413,8 @@ public class TransportImportPageTests : BunitContext
Assert.Equal("opc-main", selectedConnOpt.GetAttribute("value"));
}
/// <summary>Verifies that the map section is hidden when no mappings are required.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Map_section_hidden_when_no_required_mappings()
{
@@ -418,10 +435,12 @@ public class TransportImportPageTests : BunitContext
}
// ─────────────────────────────────────────────────────────────────────
// Test 9 (M8 E2): the operator's Map choices fold into the BundleNameMap
// Test 9: the operator's Map choices fold into the BundleNameMap
// passed to ApplyAsync — a chosen target → MapToExisting, "Create new" →
// CreateNew. Captured via the substituted IBundleImporter.
// ─────────────────────────────────────────────────────────────────────
/// <summary>Verifies that apply passes a <c>BundleNameMap</c> built from the operator's map choices.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Apply_passes_BundleNameMap_built_from_map_choices()
{
@@ -479,9 +498,11 @@ public class TransportImportPageTests : BunitContext
}
// ─────────────────────────────────────────────────────────────────────
// Test 10 (M8 E2): a Modified row whose FieldDiffJson carries a code
// Test 10: a Modified row whose FieldDiffJson carries a code
// lineDiff renders +/- lines via LineDiffView.
// ─────────────────────────────────────────────────────────────────────
/// <summary>Verifies that a modified row with a code line diff renders added and removed lines.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Modified_row_with_code_lineDiff_renders_add_and_remove_lines()
{
@@ -533,8 +554,10 @@ public class TransportImportPageTests : BunitContext
}
// ─────────────────────────────────────────────────────────────────────
// Test 11 (M8 E2): truncation marker shows when the lineDiff is truncated.
// Test 11: truncation marker shows when the lineDiff is truncated.
// ─────────────────────────────────────────────────────────────────────
/// <summary>Verifies that a modified row with a truncated line diff shows the truncation marker.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Modified_row_with_truncated_lineDiff_shows_truncation_marker()
{
@@ -579,11 +602,13 @@ public class TransportImportPageTests : BunitContext
}
// ─────────────────────────────────────────────────────────────────────
// Test 12 (M8 E2 Fix 1): changing a source site's dropdown to a target
// Test 12: changing a source site's dropdown to a target
// that lacks the previously auto-matched connection name resets that
// connection choice to CreateNew (""), and BuildNameMap therefore emits
// a CreateNew entry — not a MapToExisting for an absent connection.
// ─────────────────────────────────────────────────────────────────────
/// <summary>Verifies that changing a site choice resets connection choices the new target site lacks.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task OnSiteChoiceChanged_resets_stale_connection_choices_when_new_target_lacks_connection()
{
@@ -639,9 +664,11 @@ public class TransportImportPageTests : BunitContext
}
// ─────────────────────────────────────────────────────────────────────
// Test 13 (M8 E2 Fix 2): BackToUpload clears session/preview/Map state
// Test 13: BackToUpload clears session/preview/Map state
// so a subsequent re-upload flow cannot inherit stale data.
// ─────────────────────────────────────────────────────────────────────
/// <summary>Verifies that going back to upload clears the session, preview and map state.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task BackToUpload_clears_session_and_preview_state()
{
@@ -715,12 +742,17 @@ public class TransportImportPageTests : BunitContext
/// </summary>
private sealed class StoreBackedImporter : IBundleImporter
{
/// <summary>Gets the backing bundle session store.</summary>
public BundleSessionStore Store { get; } = new(
Microsoft.Extensions.Options.Options.Create(new TransportOptions()),
TimeProvider.System);
/// <summary>Gets the number of times <c>Abandon</c> has been called.</summary>
public int AbandonCalls { get; private set; }
/// <summary>Seeds an encrypted session directly into the store.</summary>
/// <param name="sourceEnv">The source environment name recorded on the session manifest.</param>
/// <returns>The opened session.</returns>
public BundleSession OpenSession(string sourceEnv = "prod-cluster")
{
var seed = BuildEncryptedSession(sourceEnv);
@@ -735,13 +767,16 @@ public class TransportImportPageTests : BunitContext
return Store.Open(session);
}
/// <inheritdoc />
public Task<BundleSession> LoadAsync(
Stream bundleStream, string? passphrase, CancellationToken ct = default, string? clientKey = null)
=> throw new NotSupportedException("These tests seed sessions via OpenSession().");
/// <inheritdoc />
public Task<ImportPreview> PreviewAsync(Guid sessionId, CancellationToken ct = default)
=> Task.FromResult(new ImportPreview(sessionId, new List<ImportPreviewItem>()));
/// <inheritdoc />
public Task<ImportResult> ApplyAsync(
Guid sessionId,
IReadOnlyList<ImportResolution> resolutions,
@@ -760,6 +795,7 @@ public class TransportImportPageTests : BunitContext
AuditEventCorrelation: Guid.NewGuid().ToString()));
}
/// <inheritdoc />
public void Abandon(Guid sessionId)
{
AbandonCalls++;
@@ -777,6 +813,8 @@ public class TransportImportPageTests : BunitContext
}
}
/// <summary>Verifies that disposing the wizard releases its bundle session.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Disposing_the_wizard_releases_its_bundle_session()
{
@@ -798,6 +836,8 @@ public class TransportImportPageTests : BunitContext
Assert.Null(GetField<object?>(cut.Instance, "_session"));
}
/// <summary>Verifies that going back to upload releases the bundle session.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task BackToUpload_releases_the_bundle_session()
{
@@ -827,6 +867,8 @@ public class TransportImportPageTests : BunitContext
Assert.All(content, b => Assert.Equal(0, b));
}
/// <summary>Verifies that applying then disposing releases the session exactly once without throwing.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Apply_then_dispose_releases_the_session_once_without_throwing()
{
@@ -862,6 +904,8 @@ public class TransportImportPageTests : BunitContext
Assert.Null(importer.Store.Get(session.SessionId));
}
/// <summary>Verifies that disposing one wizard leaves a concurrent circuit's session open.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Disposing_one_wizard_leaves_a_concurrent_circuits_session_open()
{
@@ -942,8 +986,8 @@ public class TransportImportPageTests : BunitContext
/// <summary>
/// Seeds the wizard at Step 2 (Passphrase) with a staged bundle file — the
/// shape after an encrypted-bundle upload completed Step 1's peek and
/// surfaced an ArgumentException ("passphrase required"). CentralUI-031:
/// the wizard now stages the upload to a temp file and only retains the
/// surfaced an ArgumentException ("passphrase required"). The
/// wizard now stages the upload to a temp file and only retains the
/// path on the component, so the test helper writes the bytes to a per-
/// test temp file and sets the path field instead of the byte[] field.
/// </summary>