using System.CommandLine; using ScadaLink.CLI.Commands; using ScadaLink.Commons.Messages.Management; namespace ScadaLink.CLI.Tests; /// /// Regression tests for CLI-013 — the command-tree wiring was untested. These tests /// build every command group and assert the tree is well-formed (every leaf has an /// action, no group is empty), and that every management command record the CLI sends /// resolves via (so command-name derivation /// never throws at runtime). /// public class CommandTreeTests { private static readonly Option Url = new("--url") { Recursive = true }; private static readonly Option Username = new("--username") { Recursive = true }; private static readonly Option Password = new("--password") { Recursive = true }; private static readonly Option Format = CliOptions.CreateFormatOption(); private static IEnumerable AllCommandGroups() => new[] { TemplateCommands.Build(Url, Format, Username, Password), InstanceCommands.Build(Url, Format, Username, Password), SiteCommands.Build(Url, Format, Username, Password), DeployCommands.Build(Url, Format, Username, Password), DataConnectionCommands.Build(Url, Format, Username, Password), ExternalSystemCommands.Build(Url, Format, Username, Password), NotificationCommands.Build(Url, Format, Username, Password), SecurityCommands.Build(Url, Format, Username, Password), AuditLogCommands.Build(Url, Format, Username, Password), HealthCommands.Build(Url, Format, Username, Password), DebugCommands.Build(Url, Format, Username, Password), SharedScriptCommands.Build(Url, Format, Username, Password), DbConnectionCommands.Build(Url, Format, Username, Password), ApiMethodCommands.Build(Url, Format, Username, Password), }; private static IEnumerable LeafCommands(Command command) { if (command.Subcommands.Count == 0) { yield return command; yield break; } foreach (var sub in command.Subcommands) foreach (var leaf in LeafCommands(sub)) yield return leaf; } [Fact] public void AllCommandGroups_Build_WithoutThrowing() { var groups = AllCommandGroups().ToList(); Assert.Equal(14, groups.Count); Assert.All(groups, g => Assert.False(string.IsNullOrWhiteSpace(g.Name))); } [Fact] public void EveryLeafCommand_HasAnAction() { // A leaf command with no action is dead wiring — invoking it would do nothing. var leaves = AllCommandGroups().SelectMany(LeafCommands).ToList(); Assert.NotEmpty(leaves); Assert.All(leaves, leaf => Assert.True(leaf.Action != null, $"Leaf command '{leaf.Name}' has no action.")); } [Theory] [InlineData(typeof(GetInstanceCommand))] [InlineData(typeof(ListSitesCommand))] [InlineData(typeof(CreateTemplateCommand))] [InlineData(typeof(SetConnectionBindingsCommand))] [InlineData(typeof(SetInstanceOverridesCommand))] [InlineData(typeof(DebugSnapshotCommand))] [InlineData(typeof(MgmtDeployInstanceCommand))] [InlineData(typeof(QueryAuditLogCommand))] public void CommandPayloadTypes_ResolveViaRegistry(Type commandType) { // GetCommandName throws ArgumentException for an unregistered type — the CLI // calls it for every command it sends, so each must round-trip. var name = ManagementCommandRegistry.GetCommandName(commandType); Assert.False(string.IsNullOrWhiteSpace(name)); Assert.Equal(commandType, ManagementCommandRegistry.Resolve(name)); } }