docs+ui: backfill XML doc comments and finish dashboard layout pass

Adds missing <summary>/<param> XML docs across 99 server, worker, and test
files so CommentChecker reports zero issues (TreatWarningsAsErrors needs the
analyzer clean). Bundles in WIP dashboard work: NavSection extraction,
MainLayout/site.css/js styling alignment, and DashboardOptions/Auth tweaks.
This commit is contained in:
Joseph Doherty
2026-05-27 14:20:10 -04:00
parent 382861c602
commit 615b487a77
110 changed files with 1473 additions and 192 deletions
@@ -44,6 +44,7 @@ public sealed class GalaxyFilterInputSafetyTests
"Pump'001",
];
/// <summary>Returns adversarial input cases for theory tests.</summary>
public static TheoryData<string> AdversarialInputCases()
{
TheoryData<string> data = [];
@@ -60,6 +61,7 @@ public sealed class GalaxyFilterInputSafetyTests
/// <c>LIKE</c>-wildcards as literals — a glob equal to the literal value matches,
/// and the same glob does not spuriously match an unrelated value.
/// </summary>
/// <param name="input">An adversarial input containing SQL metacharacters or LIKE wildcards.</param>
[Theory]
[MemberData(nameof(AdversarialInputCases))]
public void GlobMatcher_TreatsSqlMetacharactersAsLiterals(string input)
@@ -159,6 +161,7 @@ public sealed class GalaxyFilterInputSafetyTests
/// treats an adversarial glob as a literal: it never wildcard-matches the whole
/// hierarchy and never throws.
/// </summary>
/// <param name="glob">An adversarial glob containing SQL metacharacters or LIKE wildcards.</param>
[Theory]
[MemberData(nameof(AdversarialInputCases))]
public void Projector_TagNameGlob_WithAdversarialInput_DoesNotMatchEverything(string glob)
@@ -180,6 +183,7 @@ public sealed class GalaxyFilterInputSafetyTests
/// literal — an exact-match lookup that finds nothing and surfaces NotFound,
/// never matching unrelated objects or throwing an unexpected exception.
/// </summary>
/// <param name="rootTagName">An adversarial tag name containing SQL metacharacters or LIKE wildcards.</param>
[Theory]
[MemberData(nameof(AdversarialInputCases))]
public void Projector_RootTagName_WithAdversarialInput_ThrowsNotFound(string rootTagName)
@@ -198,6 +202,7 @@ public sealed class GalaxyFilterInputSafetyTests
/// Verifies an adversarial <c>TemplateChainContains</c> filter is a literal
/// substring test — it never matches unrelated template chains and never throws.
/// </summary>
/// <param name="filter">An adversarial filter containing SQL metacharacters or LIKE wildcards.</param>
[Theory]
[MemberData(nameof(AdversarialInputCases))]
public void Projector_TemplateChainContains_WithAdversarialInput_MatchesNothing(string filter)
@@ -216,6 +221,7 @@ public sealed class GalaxyFilterInputSafetyTests
/// handles an adversarial <c>TagNameGlob</c> end-to-end: the request succeeds with
/// zero matches rather than returning the whole hierarchy or faulting.
/// </summary>
/// <param name="glob">An adversarial glob containing SQL metacharacters or LIKE wildcards.</param>
[Theory]
[MemberData(nameof(AdversarialInputCases))]
public async Task DiscoverHierarchy_WithAdversarialTagNameGlob_ReturnsZeroMatches(string glob)
@@ -235,6 +241,7 @@ public sealed class GalaxyFilterInputSafetyTests
/// maps an adversarial <c>RootTagName</c> to NotFound rather than executing it as
/// a query fragment or matching unrelated objects.
/// </summary>
/// <param name="rootTagName">An adversarial tag name containing SQL metacharacters or LIKE wildcards.</param>
[Theory]
[MemberData(nameof(AdversarialInputCases))]
public async Task DiscoverHierarchy_WithAdversarialRootTagName_ReturnsNotFound(string rootTagName)
@@ -319,10 +326,13 @@ public sealed class GalaxyFilterInputSafetyTests
private sealed class StubGalaxyHierarchyCache(GalaxyHierarchyCacheEntry current) : IGalaxyHierarchyCache
{
/// <inheritdoc />
public GalaxyHierarchyCacheEntry Current { get; } = current;
/// <inheritdoc />
public Task RefreshAsync(CancellationToken cancellationToken) => Task.CompletedTask;
/// <inheritdoc />
public Task WaitForFirstLoadAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}
@@ -78,6 +78,7 @@ public sealed class GalaxyHierarchyCacheTests : IDisposable
Assert.False(GalaxyHierarchyCacheEntry.Empty.HasData);
}
/// <summary>Verifies that the hierarchy index builds paths and lookups without throwing on bad metadata.</summary>
[Fact]
public void GalaxyHierarchyIndex_BuildsPathsAndTagLookupsWithoutThrowingOnBadMetadata()
{
@@ -357,19 +358,24 @@ public sealed class GalaxyHierarchyCacheTests : IDisposable
{
private readonly TaskCompletionSource _release = new(TaskCreationOptions.RunContinuationsAsynchronously);
/// <summary>Releases the blocking task.</summary>
public void Release() => _release.TrySetResult();
/// <inheritdoc />
public Task<bool> TestConnectionAsync(CancellationToken ct = default) => Task.FromResult(false);
/// <inheritdoc />
public async Task<DateTime?> GetLastDeployTimeAsync(CancellationToken ct = default)
{
await _release.Task.WaitAsync(ct).ConfigureAwait(false);
throw new InvalidOperationException("Galaxy repository unreachable");
}
/// <inheritdoc />
public Task<List<GalaxyHierarchyRow>> GetHierarchyAsync(CancellationToken ct = default)
=> throw new InvalidOperationException("GetHierarchyAsync should not be reached");
/// <inheritdoc />
public Task<List<GalaxyAttributeRow>> GetAttributesAsync(CancellationToken ct = default)
=> throw new InvalidOperationException("GetAttributesAsync should not be reached");
}
@@ -377,9 +383,11 @@ public sealed class GalaxyHierarchyCacheTests : IDisposable
/// <summary>Snapshot store whose <see cref="SaveAsync"/> cancels the token mid-save.</summary>
private sealed class CancellingSaveStore(CancellationTokenSource cts) : IGalaxyHierarchySnapshotStore
{
/// <inheritdoc />
public Task<GalaxyHierarchySnapshot?> TryLoadAsync(CancellationToken cancellationToken)
=> Task.FromResult<GalaxyHierarchySnapshot?>(null);
/// <inheritdoc />
public Task SaveAsync(GalaxyHierarchySnapshot snapshot, CancellationToken cancellationToken)
{
cts.Cancel();
@@ -391,13 +399,17 @@ public sealed class GalaxyHierarchyCacheTests : IDisposable
/// <summary>Minimal <see cref="ILogger{T}"/> that records every emitted log entry.</summary>
private sealed class RecordingLogger<T> : ILogger<T>
{
/// <summary>Gets the list of recorded log entries.</summary>
public List<(LogLevel Level, string Message)> Entries { get; } = [];
/// <inheritdoc />
public IDisposable BeginScope<TState>(TState state)
where TState : notnull => NullScope.Instance;
/// <inheritdoc />
public bool IsEnabled(LogLevel logLevel) => true;
/// <inheritdoc />
public void Log<TState>(
LogLevel logLevel,
EventId eventId,
@@ -412,6 +424,7 @@ public sealed class GalaxyHierarchyCacheTests : IDisposable
{
public static readonly NullScope Instance = new();
/// <inheritdoc />
public void Dispose()
{
}
@@ -427,20 +440,26 @@ public sealed class GalaxyHierarchyCacheTests : IDisposable
private readonly List<GalaxyHierarchyRow> _hierarchy = hierarchy ?? [];
private readonly List<GalaxyAttributeRow> _attributes = attributes ?? [];
/// <summary>Gets the count of calls to <see cref="GetHierarchyAsync"/>.</summary>
public int GetHierarchyCount { get; private set; }
/// <summary>Gets the count of calls to <see cref="GetAttributesAsync"/>.</summary>
public int GetAttributesCount { get; private set; }
/// <inheritdoc />
public Task<bool> TestConnectionAsync(CancellationToken ct = default) => Task.FromResult(true);
/// <inheritdoc />
public Task<DateTime?> GetLastDeployTimeAsync(CancellationToken ct = default) => Task.FromResult(deployTime);
/// <inheritdoc />
public Task<List<GalaxyHierarchyRow>> GetHierarchyAsync(CancellationToken ct = default)
{
GetHierarchyCount++;
return Task.FromResult(_hierarchy);
}
/// <inheritdoc />
public Task<List<GalaxyAttributeRow>> GetAttributesAsync(CancellationToken ct = default)
{
GetAttributesCount++;
@@ -448,6 +467,7 @@ public sealed class GalaxyHierarchyCacheTests : IDisposable
}
}
/// <inheritdoc />
public void Dispose()
{
foreach (string path in _tempPaths)
@@ -16,6 +16,7 @@ namespace ZB.MOM.WW.MxGateway.Tests.Galaxy;
/// </summary>
public sealed class GalaxyHierarchyProjectorTests
{
/// <summary>Verifies that paging across a hierarchy returns every object exactly once.</summary>
[Fact]
public void Project_PagedAcrossEntireHierarchy_ReturnsEveryObjectExactlyOnce()
{
@@ -43,6 +44,7 @@ public sealed class GalaxyHierarchyProjectorTests
Assert.Equal("Object_025", collected[^1]);
}
/// <summary>Verifies that distinct filters on the same entry do not share memoized view list.</summary>
[Fact]
public void Project_DistinctFiltersOnSameEntry_DoNotShareMemoizedViewList()
{
@@ -60,6 +62,7 @@ public sealed class GalaxyHierarchyProjectorTests
Assert.Equal(10, unfiltered.TotalObjectCount);
}
/// <summary>Verifies that the same filter repeated returns identical totals.</summary>
[Fact]
public void Project_SameFilterRepeated_ReturnsIdenticalTotals()
{
@@ -85,6 +88,7 @@ public sealed class GalaxyHierarchyProjectorTests
Assert.NotEqual(first.Objects[0].TagName, second.Objects[0].TagName);
}
/// <summary>Verifies that distinct cache entries project against their own data.</summary>
[Fact]
public void Project_DistinctCacheEntries_ProjectAgainstTheirOwnData()
{
@@ -13,6 +13,7 @@ namespace ZB.MOM.WW.MxGateway.Tests.Galaxy;
/// </summary>
public sealed class GalaxyHierarchyRefreshServiceTests
{
/// <summary>Verifies that the background service does not fault when the first refresh throws a non-cancellation exception.</summary>
[Fact]
public async Task ExecuteAsync_WhenFirstRefreshThrowsNonCancellationException_DoesNotFaultBackgroundService()
{
@@ -62,13 +63,17 @@ public sealed class GalaxyHierarchyRefreshServiceTests
private readonly TaskCompletionSource firstRefreshAttempted =
new(TaskCreationOptions.RunContinuationsAsynchronously);
/// <summary>Gets the number of refresh calls.</summary>
public int RefreshCallCount { get; private set; }
/// <summary>Completes once <see cref="RefreshAsync"/> has been invoked at least once.</summary>
/// <summary>Gets a task that completes once refresh has been invoked at least once.</summary>
public Task FirstRefreshAttempted => firstRefreshAttempted.Task;
/// <summary>Gets the current cache entry.</summary>
public GalaxyHierarchyCacheEntry Current => GalaxyHierarchyCacheEntry.Empty;
/// <summary>Refreshes the cache asynchronously and throws the configured exception.</summary>
/// <param name="cancellationToken">Token to observe for cancellation.</param>
public Task RefreshAsync(CancellationToken cancellationToken)
{
RefreshCallCount++;
@@ -76,6 +81,8 @@ public sealed class GalaxyHierarchyRefreshServiceTests
throw toThrow;
}
/// <summary>Waits for the first load and completes immediately.</summary>
/// <param name="cancellationToken">Token to observe for cancellation.</param>
public Task WaitForFirstLoadAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}
}
@@ -12,6 +12,7 @@ public sealed class GalaxyHierarchySnapshotStoreTests : IDisposable
{
private readonly List<string> _tempPaths = [];
/// <summary>Verifies that snapshots are correctly saved to and loaded from disk.</summary>
[Fact]
public async Task SaveAsync_ThenTryLoadAsync_RoundTripsRows()
{
@@ -39,6 +40,7 @@ public sealed class GalaxyHierarchySnapshotStoreTests : IDisposable
Assert.Null(loaded.Attributes[1].ArrayDimension);
}
/// <summary>Verifies that loading returns null when no snapshot file exists.</summary>
[Fact]
public async Task TryLoadAsync_WhenNoFileExists_ReturnsNull()
{
@@ -47,6 +49,7 @@ public sealed class GalaxyHierarchySnapshotStoreTests : IDisposable
Assert.Null(await store.TryLoadAsync(CancellationToken.None));
}
/// <summary>Verifies that save writes nothing when persistence is disabled.</summary>
[Fact]
public async Task SaveAsync_WhenPersistenceDisabled_WritesNothing()
{
@@ -59,6 +62,7 @@ public sealed class GalaxyHierarchySnapshotStoreTests : IDisposable
Assert.Null(await store.TryLoadAsync(CancellationToken.None));
}
/// <summary>Verifies that loading returns null when the file contains invalid JSON.</summary>
[Fact]
public async Task TryLoadAsync_WhenFileIsCorruptJson_ReturnsNull()
{
@@ -69,6 +73,7 @@ public sealed class GalaxyHierarchySnapshotStoreTests : IDisposable
Assert.Null(await store.TryLoadAsync(CancellationToken.None));
}
/// <summary>Verifies that loading returns null when the schema version is unrecognized.</summary>
[Fact]
public async Task TryLoadAsync_WhenSchemaVersionUnrecognized_ReturnsNull()
{
@@ -79,6 +84,7 @@ public sealed class GalaxyHierarchySnapshotStoreTests : IDisposable
Assert.Null(await store.TryLoadAsync(CancellationToken.None));
}
/// <summary>Verifies that saving overwrites an earlier snapshot.</summary>
[Fact]
public async Task SaveAsync_OverwritesAnEarlierSnapshot()
{
@@ -159,6 +165,7 @@ public sealed class GalaxyHierarchySnapshotStoreTests : IDisposable
return path;
}
/// <inheritdoc />
public void Dispose()
{
foreach (string path in _tempPaths)