fix(commons): resolve Commons-001..004 — stale-fire race, JsonDocument lifetime, GetNullable strictness, registry symmetry

This commit is contained in:
Joseph Doherty
2026-05-16 20:58:03 -04:00
parent dba1a1b25f
commit 3e7a3d7e31
9 changed files with 501 additions and 37 deletions

View File

@@ -0,0 +1,78 @@
using System.Reflection;
using ScadaLink.Commons.Messages.Management;
namespace ScadaLink.Commons.Tests.Messages;
/// <summary>
/// Tests for <see cref="ManagementCommandRegistry"/>, including the Commons-004
/// regression: <c>GetCommandName</c> and <c>Resolve</c> must be symmetric — every
/// type for which <c>GetCommandName</c> yields a name must round-trip back to the
/// same type via <c>Resolve</c>.
/// </summary>
public class ManagementCommandRegistryTests
{
private static IEnumerable<Type> RegisteredCommandTypes() =>
typeof(ManagementEnvelope).Assembly.GetTypes()
.Where(t => t.Namespace == typeof(ManagementEnvelope).Namespace
&& t.Name.EndsWith("Command", StringComparison.Ordinal)
&& !t.IsAbstract);
[Fact]
public void GetCommandName_Resolve_RoundTrips_ForEveryRegisteredCommand()
{
foreach (var type in RegisteredCommandTypes())
{
var name = ManagementCommandRegistry.GetCommandName(type);
var resolved = ManagementCommandRegistry.Resolve(name);
Assert.Equal(type, resolved);
}
}
[Fact]
public void Resolve_KnownCommand_ReturnsType()
{
var type = ManagementCommandRegistry.Resolve("CreateSite");
Assert.Equal(typeof(CreateSiteCommand), type);
}
[Fact]
public void Resolve_UnknownCommand_ReturnsNull()
{
Assert.Null(ManagementCommandRegistry.Resolve("NoSuchCommand"));
}
[Fact]
public void Resolve_IsCaseInsensitive()
{
Assert.Equal(typeof(CreateSiteCommand), ManagementCommandRegistry.Resolve("createsite"));
}
/// <summary>
/// Commons-004: <c>GetCommandName</c> previously stripped a <c>Command</c> suffix
/// from <em>any</em> type, producing names the registry cannot resolve. It must
/// only return a name for a command type the registry actually contains.
/// </summary>
[Fact]
public void GetCommandName_UnregisteredCommandType_Throws()
{
// A *Command type that is not in the Messages.Management namespace.
Assert.Throws<ArgumentException>(
() => ManagementCommandRegistry.GetCommandName(typeof(UnregisteredFakeCommand)));
}
[Fact]
public void GetCommandName_NonCommandType_Throws()
{
Assert.Throws<ArgumentException>(
() => ManagementCommandRegistry.GetCommandName(typeof(string)));
}
[Fact]
public void GetCommandName_RegisteredCommand_ReturnsStrippedName()
{
Assert.Equal("CreateSite", ManagementCommandRegistry.GetCommandName(typeof(CreateSiteCommand)));
}
/// <summary>A *Command record outside the Management namespace, for the negative test.</summary>
private record UnregisteredFakeCommand(int Id);
}