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
@@ -6,7 +6,7 @@ using ZB.MOM.WW.ScadaBridge.Commons.Types.Enums;
namespace ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Design;
/// <summary>
/// MV-13: the shared <c>AttributeListEditor</c> reveals an element-type select
/// The shared <c>AttributeListEditor</c> reveals an element-type select
/// plus a repeatable list-value editor for structured List attributes. These are
/// real bUnit rendering/interaction tests over the self-contained component, plus
/// structural assertions pinning the TemplateEdit attribute-form wiring (the page
@@ -29,12 +29,13 @@ public class AttributeListEditorTests : BunitContext
private static string TemplateEditMarkup
=> File.ReadAllText(Path.Combine(DesignComponentsRoot, "TemplateEdit.razor"));
// M10 residual: the attribute authoring form moved out of the page into the
// The attribute authoring form moved out of the page into the
// dialog body component hosted by IDialogService.ShowAsync. Submit-side
// encoding stays on the page (it owns TemplateService).
private static string AttributeDialogMarkup
=> File.ReadAllText(Path.Combine(DesignComponentsRoot, "TemplateAttributeDialog.razor"));
/// <summary>Verifies that the editor renders an element type select offering the six valid scalar types.</summary>
[Fact]
public void Editor_RendersElementTypeSelect_WithSixValidScalars()
{
@@ -56,6 +57,7 @@ public class AttributeListEditorTests : BunitContext
Assert.DoesNotContain("List", texts);
}
/// <summary>Verifies that turning off the element type option hides the select.</summary>
[Fact]
public void ShowElementType_False_HidesTheSelect()
{
@@ -66,6 +68,7 @@ public class AttributeListEditorTests : BunitContext
Assert.Throws<ElementNotFoundException>(() => cut.Find("select.form-select"));
}
/// <summary>Verifies that the editor renders one input per row.</summary>
[Fact]
public void Editor_RendersOneInputPerRow()
{
@@ -79,6 +82,7 @@ public class AttributeListEditorTests : BunitContext
Assert.Equal("3", inputs[2].GetAttribute("value"));
}
/// <summary>Verifies that adding an element appends a row and raises the rows-changed callback.</summary>
[Fact]
public void AddElement_AppendsRow_AndRaisesRowsChanged()
{
@@ -95,6 +99,7 @@ public class AttributeListEditorTests : BunitContext
Assert.Equal("", changed[1]);
}
/// <summary>Verifies that removing an element drops its row and raises the rows-changed callback.</summary>
[Fact]
public void RemoveElement_DropsRow_AndRaisesRowsChanged()
{
@@ -112,6 +117,7 @@ public class AttributeListEditorTests : BunitContext
Assert.Equal("b", changed![0]);
}
/// <summary>Verifies that encoded rows round-trip through the codec.</summary>
[Fact]
public void EncodedRows_RoundTripThroughCodec()
{
@@ -123,6 +129,7 @@ public class AttributeListEditorTests : BunitContext
Assert.Equal(new[] { 10, 20 }, list);
}
/// <summary>Verifies that the template edit form reveals the list editor and sends the element type.</summary>
[Fact]
public void TemplateEdit_RevealsListEditor_AndSendsElementType()
{
@@ -13,7 +13,7 @@ using ExternalSystemForm = ZB.MOM.WW.ScadaBridge.CentralUI.Components.Pages.Desi
namespace ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Design;
/// <summary>
/// Bundle D drill-in test (#23 M7-T12) for the External Systems edit page.
/// Drill-in test for the External Systems edit page.
/// The page-header chip routes operators into the central Audit Log
/// pre-filtered by Target = external-system name. Create mode has nothing
/// to drill into yet, so the link is suppressed.
@@ -22,6 +22,7 @@ public class ExternalSystemFormAuditDrillinTests : BunitContext
{
private readonly IExternalSystemRepository _repo = Substitute.For<IExternalSystemRepository>();
/// <summary>Initializes the test context with a substitute repository and test authentication.</summary>
public ExternalSystemFormAuditDrillinTests()
{
Services.AddSingleton(_repo);
@@ -38,6 +39,7 @@ public class ExternalSystemFormAuditDrillinTests : BunitContext
AuthorizationPolicies.AddScadaBridgeAuthorization(Services);
}
/// <summary>Verifies that the edit page shows a recent audit activity link whose target equals the system name.</summary>
[Fact]
public void EditPage_HasRecentAuditActivityLink_WithTargetEqualToSystemName()
{
@@ -57,6 +59,7 @@ public class ExternalSystemFormAuditDrillinTests : BunitContext
});
}
/// <summary>Verifies that the create page shows no recent audit activity link.</summary>
[Fact]
public void CreatePage_HasNoRecentAuditActivityLink()
{
@@ -70,10 +73,11 @@ public class ExternalSystemFormAuditDrillinTests : BunitContext
});
}
/// <summary>Verifies that the form renders a timeout seconds input with the gateway default helper text.</summary>
[Fact]
public void Form_RendersTimeoutSecondsInput_WithGatewayDefaultHelperText()
{
// PLAN-06 Task 12: the per-system TimeoutSeconds column (Task 8) needs a
// The per-system TimeoutSeconds column needs a
// Central UI form field so Design users can actually set it.
var cut = Render<ExternalSystemForm>();
@@ -84,6 +88,7 @@ public class ExternalSystemFormAuditDrillinTests : BunitContext
});
}
/// <summary>Verifies that saving a new system passes its timeout seconds to the repository.</summary>
[Fact]
public void SavingNewSystem_WithTimeoutSeconds_PassesTimeoutSecondsToRepository()
{
@@ -105,6 +110,7 @@ public class ExternalSystemFormAuditDrillinTests : BunitContext
});
}
/// <summary>Verifies that saving an edited system updates the timeout seconds on the existing record.</summary>
[Fact]
public void SavingEditedSystem_UpdatesTimeoutSecondsOnExisting()
{
@@ -25,6 +25,7 @@ public class ExternalSystemsConnectionStringHidingTests : BunitContext
private readonly IInboundApiRepository _inbound = Substitute.For<IInboundApiRepository>();
private readonly IDialogService _dialog = Substitute.For<IDialogService>();
/// <summary>Initializes the test context and registers the services the External Systems page depends on.</summary>
public ExternalSystemsConnectionStringHidingTests()
{
Services.AddSingleton(_repo);
@@ -43,6 +44,7 @@ public class ExternalSystemsConnectionStringHidingTests : BunitContext
AuthorizationPolicies.AddScadaBridgeAuthorization(Services);
}
/// <summary>Verifies that the database connections tab does not render the connection string.</summary>
[Fact]
public void DbConnectionsTab_DoesNotRenderConnectionString()
{
@@ -7,7 +7,7 @@ using ZB.MOM.WW.ScadaBridge.CentralUI.Services;
namespace ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Design;
/// <summary>
/// M9-T31 (+#261 follow-up): the raw-JSON escape hatch in
/// The raw-JSON escape hatch in
/// <see cref="ParameterValueForm"/> (the fallback for an unresolved <c>$ref</c> /
/// unknown-type node) is a Monaco <c>json</c> editor wired with THAT FIELD's own
/// sub-schema — not the whole root object schema — so each field's editor
@@ -22,6 +22,7 @@ public class ParameterValueFormMonacoSchemaTests : BunitContext
{
private readonly ISchemaLibraryQueryService _library = Substitute.For<ISchemaLibraryQueryService>();
/// <summary>Initializes a new instance of the <see cref="ParameterValueFormMonacoSchemaTests"/> class.</summary>
public ParameterValueFormMonacoSchemaTests()
{
// The escape-hatch surface renders a MonacoEditor whose JS interop is not
@@ -33,6 +34,7 @@ public class ParameterValueFormMonacoSchemaTests : BunitContext
Services.AddSingleton(_library);
}
/// <summary>Verifies the case: escape Hatch, renders Monaco Json Editor, not Plain Textarea.</summary>
[Fact]
public void EscapeHatch_RendersMonacoJsonEditor_NotPlainTextarea()
{
@@ -57,6 +59,7 @@ public class ParameterValueFormMonacoSchemaTests : BunitContext
Assert.Empty(cut.FindAll("textarea"));
}
/// <summary>Verifies the case: escape Hatch, monaco Editor, receives Field Sub Schema, not Root Schema.</summary>
[Fact]
public void EscapeHatch_MonacoEditor_ReceivesFieldSubSchema_NotRootSchema()
{
@@ -106,6 +109,7 @@ public class ParameterValueFormMonacoSchemaTests : BunitContext
Assert.DoesNotContain("$ref", jsonSchema!);
}
/// <summary>Verifies the case: escape Hatch, with Resolvable Sibling Object, scopes Field Editor To Its Own Fragment.</summary>
[Fact]
public void EscapeHatch_WithResolvableSiblingObject_ScopesFieldEditorToItsOwnFragment()
{
@@ -143,6 +147,7 @@ public class ParameterValueFormMonacoSchemaTests : BunitContext
Assert.DoesNotContain("\"id\"", jsonSchema!);
}
/// <summary>Verifies the case: multiple Escape Hatch Fields, each Editor Receives Its Own Field Fragment, not Root Schema.</summary>
[Fact]
public void MultipleEscapeHatchFields_EachEditorReceivesItsOwnFieldFragment_NotRootSchema()
{
@@ -182,6 +187,7 @@ public class ParameterValueFormMonacoSchemaTests : BunitContext
}
}
/// <summary>Verifies the case: multiple Escape Hatch Fields, do Not Leak AResolvable Siblings Shape.</summary>
[Fact]
public void MultipleEscapeHatchFields_DoNotLeakAResolvableSiblingsShape()
{
@@ -7,7 +7,7 @@ using ZB.MOM.WW.ScadaBridge.CentralUI.Services;
namespace ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Design;
/// <summary>
/// M9-T30: <c>ParameterValueForm</c> renders typed nested inputs for object and
/// <c>ParameterValueForm</c> renders typed nested inputs for object and
/// list parameters (replacing the raw-JSON textarea fallback), driven by the
/// declared schema (with <c>{"$ref":"lib:Name"}</c> resolved via
/// <see cref="ISchemaLibraryQueryService"/>), with per-field validation, and
@@ -19,6 +19,7 @@ public class ParameterValueFormTests : BunitContext
{
private readonly ISchemaLibraryQueryService _library = Substitute.For<ISchemaLibraryQueryService>();
/// <summary>Initializes a new instance of the <c>ParameterValueFormTests</c> class.</summary>
public ParameterValueFormTests()
{
// Default: empty library (no $ref entries). Individual tests override.
@@ -56,6 +57,7 @@ public class ParameterValueFormTests : BunitContext
}
""";
/// <summary>Verifies that an object parameter renders one input per field instead of a raw textarea.</summary>
[Fact]
public void ObjectParameter_RendersPerFieldInputs_NotRawTextarea()
{
@@ -78,6 +80,7 @@ public class ParameterValueFormTests : BunitContext
Assert.Contains("name", cut.Markup);
}
/// <summary>Verifies that an object parameter round-trips to the canonical nested JSON shape.</summary>
[Fact]
public void ObjectParameter_RoundTripsToCanonicalNestedJsonShape()
{
@@ -101,6 +104,7 @@ public class ParameterValueFormTests : BunitContext
Assert.Equal("widget", order["name"]);
}
/// <summary>Verifies that a list parameter renders typed item rows with add and remove controls.</summary>
[Fact]
public void ListParameter_RendersAddRemoveTypedItemRows()
{
@@ -131,6 +135,7 @@ public class ParameterValueFormTests : BunitContext
Assert.Empty(tagsAfter);
}
/// <summary>Verifies that a parameter containing a reference renders the resolved shape.</summary>
[Fact]
public void RefBearingParameter_RendersResolvedShape()
{
@@ -169,6 +174,7 @@ public class ParameterValueFormTests : BunitContext
Assert.Equal(2, cut.FindAll("input[type=text]").Count);
}
/// <summary>Verifies that a per-field validation error is shown inline.</summary>
[Fact]
public void PerFieldValidationError_SurfacesInline()
{
@@ -185,7 +191,8 @@ public class ParameterValueFormTests : BunitContext
Assert.NotEmpty(cut.FindAll(".text-danger"));
}
// M1 — top-level $ref: empty-state guard must key off resolved fields, not _shapes
// Top-level $ref: empty-state guard must key off resolved fields, not _shapes
/// <summary>Verifies that a top-level reference resolving to an object renders its fields rather than an empty state.</summary>
[Fact]
public void TopLevelRef_ResolvesToObject_RendersFields_NotEmptyState()
{
@@ -228,6 +235,7 @@ public class ParameterValueFormTests : BunitContext
// is cleared on invalid input, not the containing dict). This is the scenario the
// ShiftDict fix is designed for: "rows[1].qty" → "rows[0].qty" when rows[0] is
// removed, so the error/raw-text follows the item rather than being wiped.
/// <summary>Verifies that removing a list item shifts the nested raw text of later items instead of wiping it.</summary>
[Fact]
public void ListItemRemoval_ShiftsNestedRawTextOfLaterItems_NotWiped()
{
@@ -283,6 +291,7 @@ public class ParameterValueFormTests : BunitContext
Assert.NotEmpty(cut.FindAll(".text-danger"));
}
/// <summary>Verifies that the valid-changed callback reports false on a parse error and true once it is fixed.</summary>
[Fact]
public void ValidChanged_ReportsFalseOnAParseError_AndTrueOnceFixed()
{
@@ -298,6 +307,7 @@ public class ParameterValueFormTests : BunitContext
Assert.True(valid.Last());
}
/// <summary>Verifies that the valid-changed callback reports false on first render when a required field is empty.</summary>
[Fact]
public void ValidChanged_ReportsFalseOnFirstRender_WhenARequiredFieldIsEmpty()
{
@@ -315,6 +325,7 @@ public class ParameterValueFormTests : BunitContext
Assert.Empty(cut.FindAll(".text-danger"));
}
/// <summary>Verifies that the valid-changed callback reports true on first render when nothing is required.</summary>
[Fact]
public void ValidChanged_ReportsTrueOnFirstRender_WhenNothingIsRequired()
{
@@ -12,7 +12,7 @@ using SchemaLibraryPage = ZB.MOM.WW.ScadaBridge.CentralUI.Components.Pages.Desig
namespace ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Design;
/// <summary>
/// bUnit tests for the Schema Library page (M9-T32c). The page lists the reusable named
/// bUnit tests for the Schema Library page. The page lists the reusable named
/// JSON-Schema library entries, authors create/edit via the shared <c>SchemaBuilder</c>
/// component, and deletes with a confirm — every mutation dispatched through
/// <see cref="ISchemaLibraryService"/> (the guard-running ManagementActor path), never a
@@ -23,6 +23,7 @@ public class SchemaLibraryPageTests : BunitContext
{
private readonly ISchemaLibraryService _service = Substitute.For<ISchemaLibraryService>();
/// <summary>Initializes the test context with a substituted schema library service and an auto-confirming dialog service.</summary>
public SchemaLibraryPageTests()
{
Services.AddSingleton(_service);
@@ -51,6 +52,7 @@ public class SchemaLibraryPageTests : BunitContext
_service.ListAsync(Arg.Any<CancellationToken>())
.Returns(Task.FromResult<IReadOnlyList<SharedSchema>>(schemas.ToList()));
/// <summary>Verifies that the page renders the empty state when there are no schemas.</summary>
[Fact]
public void Renders_EmptyState_WhenNoSchemas()
{
@@ -60,6 +62,7 @@ public class SchemaLibraryPageTests : BunitContext
Assert.Contains("No library schemas defined", cut.Markup));
}
/// <summary>Verifies that existing schemas are listed together with their library reference.</summary>
[Fact]
public void Lists_ExistingSchemas_WithLibReference()
{
@@ -78,6 +81,7 @@ public class SchemaLibraryPageTests : BunitContext
});
}
/// <summary>Verifies that choosing New Schema opens the editor with the schema builder.</summary>
[Fact]
public void NewSchema_OpensEditor_WithSchemaBuilder()
{
@@ -92,6 +96,7 @@ public class SchemaLibraryPageTests : BunitContext
Assert.NotNull(cut.FindComponent<SchemaBuilder>());
}
/// <summary>Verifies that creating a schema dispatches a create command carrying the name and schema.</summary>
[Fact]
public void Create_DispatchesCreateCommand_WithNameAndSchema()
{
@@ -112,6 +117,7 @@ public class SchemaLibraryPageTests : BunitContext
"Address", Arg.Any<string?>(), Arg.Any<string>(), Arg.Any<CancellationToken>()));
}
/// <summary>Verifies that a guard error from a create is shown inline and the editor stays open.</summary>
[Fact]
public void Create_GuardError_IsShownInline_AndEditorStaysOpen()
{
@@ -133,6 +139,7 @@ public class SchemaLibraryPageTests : BunitContext
});
}
/// <summary>Verifies that saving with an empty name dispatches no command.</summary>
[Fact]
public void EmptyName_DoesNotDispatch()
{
@@ -148,6 +155,7 @@ public class SchemaLibraryPageTests : BunitContext
Arg.Any<string>(), Arg.Any<string?>(), Arg.Any<string>(), Arg.Any<CancellationToken>());
}
/// <summary>Verifies that deleting a schema confirms first, dispatches a delete command and reloads the list.</summary>
[Fact]
public void Delete_ConfirmsThenDispatchesDeleteCommand_AndReloads()
{
@@ -168,6 +176,7 @@ public class SchemaLibraryPageTests : BunitContext
});
}
/// <summary>Verifies that editing a schema opens the editor and dispatches an update command.</summary>
[Fact]
public void Edit_OpensEditor_AndDispatchesUpdateCommand()
{
@@ -188,10 +197,11 @@ public class SchemaLibraryPageTests : BunitContext
9, "Address", Arg.Any<string?>(), Arg.Any<string>(), Arg.Any<CancellationToken>()));
}
/// <summary>Verifies that row actions are disabled while the editor is open so the row under edit cannot be deleted.</summary>
[Fact]
public void Editing_DisablesRowActions_SoTheRowUnderEditCannotBeDeleted()
{
// #260: while the edit form is open the list still shows the row, but its
// While the edit form is open the list still shows the row, but its
// Edit/Delete actions must be disabled so the row under edit (or a sibling)
// can't be deleted out from under the form.
SeedSchemas(new SharedSchema { Id = 9, Name = "Address", Scope = "us", SchemaJson = "{\"type\":\"object\"}" });
@@ -211,19 +221,28 @@ public class SchemaLibraryPageTests : BunitContext
/// <summary>A dialog service that auto-confirms, so the delete path runs end-to-end.</summary>
private sealed class AlwaysConfirmDialogService : IDialogService
{
/// <inheritdoc />
public Task<bool> ConfirmAsync(string title, string message, bool danger = false, string? confirmLabel = null)
=> Task.FromResult(true);
// Register row 75 added a DialogSeverity overload. This stub auto-confirms
// regardless of severity — it exists to let action paths run end to end, not to
// assert anything about styling.
/// <inheritdoc />
public Task<bool> ConfirmAsync(string title, string message, DialogSeverity severity, string? confirmLabel = null)
=> Task.FromResult(true);
/// <inheritdoc />
public Task<string?> PromptAsync(
string title, string label, string initialValue = "", string? placeholder = null)
=> Task.FromResult<string?>(null);
/// <summary>Returns the default result without showing a dialog.</summary>
/// <typeparam name="TResult">The type of result the dialog would produce.</typeparam>
/// <param name="title">The dialog title.</param>
/// <param name="body">The dialog body fragment.</param>
/// <param name="size">The optional dialog size.</param>
/// <returns>A task whose result is the default value of <typeparamref name="TResult"/>.</returns>
public Task<TResult?> ShowAsync<TResult>(
string title,
Microsoft.AspNetCore.Components.RenderFragment<DialogContext<TResult>> body,
@@ -7,7 +7,7 @@ using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Repositories;
namespace ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Design;
/// <summary>
/// Tests for the schema-library read-accessor (M9-T32c) that T30's schema-driven
/// Tests for the schema-library read-accessor that the schema-driven
/// value-entry forms reuse to resolve <c>{"$ref":"lib:Name"}</c> pointers. It projects
/// <see cref="ISharedSchemaRepository"/> onto a name → schema-JSON map (and a single-name
/// lookup) over a fresh DI scope. The repository is substituted and registered scoped so
@@ -25,6 +25,8 @@ public class SchemaLibraryQueryServiceTests
return (service, repo);
}
/// <summary>Verifies that the schema map associates each library name with its schema JSON.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task GetSchemaMapAsync_MapsNameToSchemaJson()
{
@@ -42,6 +44,8 @@ public class SchemaLibraryQueryServiceTests
Assert.Equal("{\"type\":\"array\"}", map["GeoPoint"]);
}
/// <summary>Verifies that an empty library yields an empty schema map.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task GetSchemaMapAsync_EmptyLibrary_ReturnsEmptyMap()
{
@@ -53,6 +57,8 @@ public class SchemaLibraryQueryServiceTests
Assert.Empty(map);
}
/// <summary>Verifies that resolving a known name returns its schema JSON.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task ResolveAsync_KnownName_ReturnsSchemaJson()
{
@@ -65,6 +71,8 @@ public class SchemaLibraryQueryServiceTests
Assert.Equal("{\"type\":\"object\"}", json);
}
/// <summary>Verifies that resolving an unknown name returns null.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task ResolveAsync_UnknownName_ReturnsNull()
{
@@ -74,6 +82,8 @@ public class SchemaLibraryQueryServiceTests
Assert.Null(await service.ResolveAsync("Missing"));
}
/// <summary>Verifies that resolving an empty name returns null without querying the repository.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task ResolveAsync_EmptyName_ReturnsNull_WithoutHittingRepo()
{
@@ -17,7 +17,7 @@ using SharedScriptFormPage = ZB.MOM.WW.ScadaBridge.CentralUI.Components.Pages.De
namespace ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Design;
/// <summary>
/// Regression tests for arch-review P6-12. <c>ApiMethodForm</c> and
/// Regression tests for the sandbox-run cancellation defect. <c>ApiMethodForm</c> and
/// <c>SharedScriptForm</c> run a Test Run sandbox script via
/// <c>AnalysisService.RunInSandboxAsync(request, _runCts.Token)</c> but — unlike
/// <c>TemplateScriptDialog</c>, which cancels/disposes <c>_runCts</c> from an
@@ -36,7 +36,7 @@ namespace ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Design;
/// requires <c>ScriptAnalysisService.RunInSandboxAsync</c> to be <c>virtual</c> —
/// a test-only seam added alongside this fix (mirroring the pre-existing
/// <c>virtual</c> on <c>DebugStreamService.StartStreamAsync</c>/<c>StopStream</c>),
/// not itself part of the P6-12 defect or its fix.
/// not itself part of the defect or its fix.
/// </para>
/// <para>
/// <b>Proof of failure:</b> stashing only the two <c>.razor</c> changes (leaving
@@ -51,6 +51,7 @@ namespace ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Design;
/// </summary>
public class ApiMethodFormSandboxDisposalTests : BunitContext
{
/// <summary>Initializes a new instance of <c>GatedScriptAnalysisService</c>.</summary>
private (IRenderedComponent<ApiMethodFormPage> Cut, GatedScriptAnalysisService Sandbox) RenderPage()
{
// ApiMethodForm mounts a MonacoEditor unconditionally; let bUnit answer its
@@ -99,6 +100,8 @@ public class ApiMethodFormSandboxDisposalTests : BunitContext
typeof(ApiMethodFormPage).GetField(name, BindingFlags.Instance | BindingFlags.NonPublic)!
.GetValue(page);
/// <summary>Verifies that dispose mid run cancels the sandbox run token.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Dispose_MidRun_CancelsTheSandboxRunToken()
{
@@ -124,6 +127,8 @@ public class ApiMethodFormSandboxDisposalTests : BunitContext
await run.WaitAsync(TimeSpan.FromSeconds(5));
}
/// <summary>Verifies that dispose mid run continuation is a no op.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Dispose_MidRun_ContinuationIsANoOp()
{
@@ -198,6 +203,8 @@ public class SharedScriptFormSandboxDisposalTests : BunitContext
typeof(SharedScriptFormPage).GetField(name, BindingFlags.Instance | BindingFlags.NonPublic)!
.GetValue(page);
/// <summary>Verifies that dispose mid run cancels the sandbox run token.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Dispose_MidRun_CancelsTheSandboxRunToken()
{
@@ -220,6 +227,8 @@ public class SharedScriptFormSandboxDisposalTests : BunitContext
await run.WaitAsync(TimeSpan.FromSeconds(5));
}
/// <summary>Verifies that dispose mid run continuation is a no op.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task Dispose_MidRun_ContinuationIsANoOp()
{
@@ -260,6 +269,7 @@ internal sealed class GatedScriptAnalysisService : ScriptAnalysisService
private readonly TaskCompletionSource _entered =
new(TaskCreationOptions.RunContinuationsAsynchronously);
/// <summary>Initializes a new instance of <c>GatedScriptAnalysisService</c>.</summary>
public GatedScriptAnalysisService()
: base(
Substitute.For<ISharedScriptCatalog>(),
@@ -278,6 +288,7 @@ internal sealed class GatedScriptAnalysisService : ScriptAnalysisService
public void ReleaseRun() => _gate.TrySetResult(
new SandboxRunResult(true, "1", "int", "", null, SandboxErrorKind.None, 1, null));
/// <inheritdoc />
public override async Task<SandboxRunResult> RunInSandboxAsync(SandboxRunRequest request, CancellationToken ct)
{
LastToken = ct;
@@ -30,6 +30,7 @@ public class TemplateAlarmDialogMesReportableTests
private static string TemplateEditMarkup
=> File.ReadAllText(Path.Combine(DesignComponentsRoot, "TemplateEdit.razor"));
/// <summary>Verifies that the alarm dialog has a MES-reportable checkbox.</summary>
[Fact]
public void AlarmDialog_HasMesReportableCheckbox()
{
@@ -39,6 +40,7 @@ public class TemplateAlarmDialogMesReportableTests
Assert.Contains("MES reportable", markup);
}
/// <summary>Verifies that the alarm dialog threads the MES-reportable flag through its parameter and draft.</summary>
[Fact]
public void AlarmDialog_ThreadsMesReportableThroughParameterAndDraft()
{
@@ -48,6 +50,7 @@ public class TemplateAlarmDialogMesReportableTests
Assert.Contains("bool IsMesReportable", markup);
}
/// <summary>Verifies that the alarms tab has a MES column.</summary>
[Fact]
public void AlarmsTab_HasMesColumn()
{
@@ -57,6 +60,7 @@ public class TemplateAlarmDialogMesReportableTests
Assert.Contains("alarm.IsMesReportable", markup);
}
/// <summary>Verifies that the alarms tab passes the MES-reportable flag into and out of the dialog.</summary>
[Fact]
public void AlarmsTab_PassesMesReportableIntoAndOutOfTheDialog()
{
@@ -20,7 +20,7 @@ using TemplateEditPage = ZB.MOM.WW.ScadaBridge.CentralUI.Components.Pages.Design
namespace ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Design;
/// <summary>
/// bUnit tests for the template editor's READ-ONLY inheritance preview (M9-T26b):
/// bUnit tests for the template editor's READ-ONLY inheritance preview:
/// rendering the FULL transitively-resolved inherited member set (not just the
/// immediate base) annotated with origin, plus a read-only base-changed staleness
/// banner. The resolve query is dispatched through
@@ -41,6 +41,7 @@ public class TemplateEditInheritedSetTests : BunitContext
private const int DerivedId = 30;
private const int BaseId = 20;
/// <summary>Initializes the bUnit context and registers the fakes and services the template editor needs.</summary>
public TemplateEditInheritedSetTests()
{
Services.AddSingleton(_repo);
@@ -121,6 +122,7 @@ public class TemplateEditInheritedSetTests : BunitContext
_resolve.ResolveAsync(DerivedId, Arg.Any<CancellationToken>())
.Returns(Task.FromResult<ResolvedTemplateMembers?>(resolved));
/// <summary>Verifies that transitively inherited members are rendered with an origin annotation.</summary>
[Fact]
public void Renders_TransitivelyInheritedMembers_WithOriginAnnotation()
{
@@ -167,6 +169,7 @@ public class TemplateEditInheritedSetTests : BunitContext
});
}
/// <summary>Verifies that the effective alarm trigger configuration is rendered from the resolved set.</summary>
[Fact]
public void Renders_EffectiveAlarmTriggerConfiguration_FromResolvedSet()
{
@@ -203,6 +206,7 @@ public class TemplateEditInheritedSetTests : BunitContext
});
}
/// <summary>Verifies that the staleness banner is shown when the resolved set is stale.</summary>
[Fact]
public void Shows_StalenessBanner_WhenResolvedSetIsStale()
{
@@ -235,6 +239,7 @@ public class TemplateEditInheritedSetTests : BunitContext
});
}
/// <summary>Verifies that no staleness banner is shown when the resolved set is not stale.</summary>
[Fact]
public void NoStalenessBanner_WhenResolvedSetIsNotStale()
{
@@ -1,7 +1,7 @@
namespace ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Design;
/// <summary>
/// Task 24: the template editor exposes a Native Alarm Sources subsection (a new
/// The template editor exposes a Native Alarm Sources subsection (a new
/// tab) for authoring read-only native alarm bindings. <c>TemplateEdit</c> is a
/// heavyweight page (~10 injected services with their own graphs); like the other
/// TemplateEdit coverage in this suite (see <c>TestRunWarningTests</c>), these are
@@ -28,13 +28,14 @@ public class TemplateNativeAlarmSourceEditorTests
private static string TemplateEditMarkup
=> File.ReadAllText(Path.Combine(DesignComponentsRoot, "TemplateEdit.razor"));
// M10 residual: the authoring form moved out of the page into the dialog body
// The authoring form moved out of the page into the dialog body
// component hosted by IDialogService.ShowAsync. The field-level assertions
// below follow it there; the tab, the connection filtering, and the CRUD
// wiring all still live on the page.
private static string NativeSourceDialogMarkup
=> File.ReadAllText(Path.Combine(DesignComponentsRoot, "TemplateNativeAlarmSourceDialog.razor"));
/// <summary>Verifies that the template editor has a Native Alarms tab.</summary>
[Fact]
public void TemplateEditor_HasNativeAlarmsTab()
{
@@ -45,6 +46,7 @@ public class TemplateNativeAlarmSourceEditorTests
Assert.Contains("Native Alarm Sources", markup);
}
/// <summary>Verifies that the native alarms form has connection, source filter and lock fields.</summary>
[Fact]
public void NativeAlarmsForm_HasConnectionSourceFilterAndLockFields()
{
@@ -67,10 +69,11 @@ public class TemplateNativeAlarmSourceEditorTests
Assert.Contains("@bind=\"_nasIsLocked\"", dialogMarkup);
}
/// <summary>Verifies that the native alarms form is hosted by the dialog service rather than embedded in the page.</summary>
[Fact]
public void NativeAlarmsForm_IsHostedByTheDialogService()
{
// M10 residual: the page-embedded modal is gone — the form opens through
// The page-embedded modal is gone — the form opens through
// IDialogService.ShowAsync so the host owns the backdrop, focus trap,
// Escape, and focus restoration.
var pageMarkup = TemplateEditMarkup;
@@ -83,6 +86,7 @@ public class TemplateNativeAlarmSourceEditorTests
Assert.Contains("DialogContext<bool> Context", dialogMarkup);
}
/// <summary>Verifies that native alarm add, update and delete are wired to the repository followed by a save.</summary>
[Fact]
public void NativeAlarmsCrud_WiresRepositoryAddUpdateDeleteWithSave()
{
@@ -1,7 +1,7 @@
namespace ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Design;
/// <summary>
/// Regression tests for CentralUI-014. Test Run wires <c>External</c>,
/// Regression tests for the Test Run side-effect warning. Test Run wires <c>External</c>,
/// <c>Database</c>, and <c>Notify</c> to central's real services, so a Test Run
/// has production-equivalent side effects. The finding asked, at minimum, that
/// this blast radius be surfaced to the user. The Test Run panels in
@@ -29,9 +29,11 @@ public class TestRunWarningTests
private static string Read(string fileName)
=> File.ReadAllText(Path.Combine(SrcRoot, fileName));
// M10 residual: the template Test Run panel moved out of TemplateEdit.razor
// The template Test Run panel moved out of TemplateEdit.razor
// into TemplateScriptDialog.razor when the page-embedded script modal was
// migrated to the IDialogService host. The warning travelled with it.
/// <summary>Verifies that a Test Run panel with a real I/O surface shows the real I/O badge and warning.</summary>
/// <param name="razorFile">The Razor file containing the Test Run panel.</param>
[Theory]
[InlineData("SharedScriptForm.razor")]
[InlineData("TemplateScriptDialog.razor")]
@@ -47,6 +49,7 @@ public class TestRunWarningTests
Assert.Contains("Side effects are permanent", markup);
}
/// <summary>Verifies that the API method form Test Run shows no real I/O badge because the inbound API has no side-effect surface.</summary>
[Fact]
public void ApiMethodForm_TestRun_HasNoRealIoBadge_BecauseInboundApiHasNoSideEffectSurface()
{